Skip to content

Commit 5ca3acd

Browse files
committed
fix: bypass proxies for subscription oauth
1 parent 6041a2e commit 5ca3acd

4 files changed

Lines changed: 41 additions & 3 deletions

File tree

core/internal/buildinfo/buildinfo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "strings"
44

55
// Set at link time via -ldflags (see .goreleaser.yaml).
66
var (
7-
Version = "dev0.1.92"
7+
Version = "dev0.1.93"
88
Commit = "none"
99
Date = "unknown"
1010
)

core/internal/subscriptionauth/oauth.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ const (
4848
// claudeTokenURL is a var (not const) so tests can point it at a local server.
4949
var claudeTokenURL = "https://platform.claude.com/v1/oauth/token"
5050

51+
// oauthHTTPClient deliberately ignores HTTP_PROXY/HTTPS_PROXY/ALL_PROXY.
52+
// OAuth callback/token/profile traffic should not be routed through user API proxies.
53+
var oauthHTTPClient = &http.Client{Transport: oauthDirectTransport()}
54+
55+
func oauthDirectTransport() *http.Transport {
56+
transport := http.DefaultTransport.(*http.Transport).Clone()
57+
transport.Proxy = nil
58+
return transport
59+
}
60+
5161
type LoginResult struct {
5262
OK bool `json:"ok"`
5363
LoggedIn bool `json:"loggedIn,omitempty"`
@@ -388,7 +398,7 @@ func enrichClaudeProfile(ctx context.Context, creds *tokenCredentials) error {
388398
}
389399
req.Header.Set("Authorization", "Bearer "+creds.Access)
390400
req.Header.Set("Accept", "application/json")
391-
resp, err := http.DefaultClient.Do(req)
401+
resp, err := oauthHTTPClient.Do(req)
392402
if err != nil {
393403
return err
394404
}
@@ -452,7 +462,7 @@ func postForm(ctx context.Context, rawURL string, form url.Values, dest any) err
452462
}
453463

454464
func doJSON(req *http.Request, dest any, label string) error {
455-
resp, err := http.DefaultClient.Do(req)
465+
resp, err := oauthHTTPClient.Do(req)
456466
if err != nil {
457467
return err
458468
}

core/internal/subscriptionauth/oauth_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ import (
1414
"testing"
1515
)
1616

17+
func TestOAuthHTTPClientBypassesEnvironmentProxy(t *testing.T) {
18+
transport, ok := oauthHTTPClient.Transport.(*http.Transport)
19+
if !ok {
20+
t.Fatalf("oauth transport = %T, want *http.Transport", oauthHTTPClient.Transport)
21+
}
22+
if transport.Proxy != nil {
23+
t.Fatal("oauth HTTP client must bypass environment proxy settings")
24+
}
25+
}
26+
1727
func TestGeneratePKCEChallenge(t *testing.T) {
1828
pair, err := generatePKCE()
1929
if err != nil {

electron/clovapi-desktop.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,23 @@ function agentUninstall(kind) {
163163
return runDesktopAsync(["agents", "uninstall", "--cli", String(kind || "")], { timeout: 10 * 60 * 1000 });
164164
}
165165

166+
function authLoginEnv() {
167+
const bypass = ["127.0.0.1", "localhost", "::1"].join(",");
168+
const merge = (value) => {
169+
const current = String(value || "").trim();
170+
if (!current) return bypass;
171+
const parts = current.split(",").map((part) => part.trim()).filter(Boolean);
172+
for (const host of bypass.split(",")) {
173+
if (!parts.some((part) => part.toLowerCase() === host.toLowerCase())) parts.push(host);
174+
}
175+
return parts.join(",");
176+
};
177+
return {
178+
...process.env,
179+
NO_PROXY: merge(process.env.NO_PROXY),
180+
no_proxy: merge(process.env.no_proxy),
181+
};
182+
}
166183
function authStatus() {
167184
return runAuthAsync(["status"]);
168185
}
@@ -176,6 +193,7 @@ async function authLogin(provider) {
176193
cancelKey: providerId,
177194
onOutput: outputHandler,
178195
timeout: AUTH_LOGIN_TIMEOUT,
196+
env: authLoginEnv(),
179197
});
180198
if (result.cancelled) {
181199
return { ok: false, cancelled: true, error: "已取消登录" };

0 commit comments

Comments
 (0)