mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-10-25 00:56:52 +08:00
84 lines
3.1 KiB
Go
84 lines
3.1 KiB
Go
package pluginstore
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v8/internal/githubauth"
|
|
)
|
|
|
|
func TestGlobalGitHubTokenAuth(t *testing.T) {
|
|
githubauth.SetToken("global-token")
|
|
t.Cleanup(func() { githubauth.SetToken("") })
|
|
const apiURL = "https://api.github.com/repos/owner/plugin/releases/assets/1"
|
|
for _, tc := range []struct {
|
|
name string
|
|
client Client
|
|
want string
|
|
}{
|
|
{name: "global", want: "Bearer global-token"},
|
|
{name: "explicit none", client: Client{Auth: []AuthConfig{{Match: "https://api.github.com/", Type: AuthTypeNone}}}},
|
|
{name: "resolved", client: Client{ResolvedAuth: []ResolvedAuthConfig{{Match: "https://api.github.com/", Type: AuthTypeGitHubToken, Token: Secret("specific-token")}}}, want: "Bearer specific-token"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
headers, authenticated, err := tc.client.authHeaders(apiURL, RequestKindArtifact)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if headers.Get("Authorization") != tc.want || authenticated != (tc.want != "") {
|
|
t.Fatal("incorrect credential selection")
|
|
}
|
|
if tc.client.releaseAssetAPIAuthenticated(apiURL) != (tc.want != "") {
|
|
t.Fatal("asset API selection ignored credentials")
|
|
}
|
|
})
|
|
}
|
|
client := Client{}
|
|
plugin := Plugin{Repository: "https://github.com/owner/plugin"}
|
|
prepared, key, err := client.PrepareLatestRelease(plugin)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
githubauth.SetToken("rotated-token")
|
|
nextKey, err := client.LatestReleaseCacheKey(plugin)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if key == nextKey || strings.Contains(key, "global-token") {
|
|
t.Fatal("cache identity must isolate credentials without exposing tokens")
|
|
}
|
|
headers, _, err := prepared.authHeaders("https://api.github.com/repos/owner/plugin/releases/latest", RequestKindMetadata)
|
|
if err != nil || headers.Get("Authorization") != "Bearer global-token" {
|
|
t.Fatal("prepared credentials were not snapshotted")
|
|
}
|
|
}
|
|
|
|
func TestGlobalGitHubTokenDownloadRedirect(t *testing.T) {
|
|
githubauth.SetToken("global-token")
|
|
t.Cleanup(func() { githubauth.SetToken("") })
|
|
calls := 0
|
|
client := Client{HTTPClient: pluginIdentityDoerFunc(func(req *http.Request) (*http.Response, error) {
|
|
calls++
|
|
if calls == 1 {
|
|
if req.URL.Host != "api.github.com" || req.Header.Get("Authorization") != "Bearer global-token" {
|
|
t.Fatal("asset API did not receive global credential")
|
|
}
|
|
return &http.Response{StatusCode: http.StatusFound, Header: http.Header{"Location": []string{"https://downloads.example/plugin.zip"}}, Body: io.NopCloser(strings.NewReader(""))}, nil
|
|
}
|
|
if req.Header.Get("Authorization") != "" {
|
|
t.Fatal("global credential leaked across redirect")
|
|
}
|
|
return &http.Response{StatusCode: http.StatusOK, Header: make(http.Header), Body: io.NopCloser(strings.NewReader("artifact"))}, nil
|
|
})}
|
|
data, err := client.DownloadAsset(context.Background(), ReleaseAsset{APIURL: "https://api.github.com/repos/owner/plugin/releases/assets/1", BrowserDownloadURL: "https://github.com/owner/plugin/releases/download/v1/plugin.zip"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(data) != "artifact" || calls != 2 {
|
|
t.Fatal("unexpected artifact download")
|
|
}
|
|
}
|