mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-09-03 14:39:26 +08:00
fix(codex): align websocket cloaking headers
This commit is contained in:
@@ -220,7 +220,7 @@ codex:
|
||||
# Some superstitious users believe request tracking identifiers can be used
|
||||
# as evidence for TOS enforcement bans; this option only satisfies those odd concerns.
|
||||
identity-confuse: false
|
||||
# Disable forcing the official Codex User-Agent and Originator headers on HTTP requests.
|
||||
# Disable forcing the official Codex User-Agent and Originator headers on HTTP/SSE and WebSocket requests.
|
||||
disable-codex-cloaking: false
|
||||
# When true, optimize Codex Desktop and codex-tui requests for multi-agent v2.
|
||||
# This refreshes Codex spawn_agent model details, removes message parameter encryption,
|
||||
|
||||
@@ -127,7 +127,7 @@ type XAIConfig struct {
|
||||
// CodexConfig configures provider-wide Codex request behavior.
|
||||
type CodexConfig struct {
|
||||
IdentityConfuse bool `yaml:"identity-confuse" json:"identity-confuse"`
|
||||
// DisableCodexCloaking disables forcing the official Codex identity headers on HTTP requests.
|
||||
// DisableCodexCloaking disables forcing the official Codex identity headers on HTTP/SSE and WebSocket requests.
|
||||
DisableCodexCloaking bool `yaml:"disable-codex-cloaking" json:"disable-codex-cloaking"`
|
||||
// OptimizeMultiAgentV2 optimizes official Codex multi-agent requests.
|
||||
OptimizeMultiAgentV2 bool `yaml:"optimize-multi-agent-v2" json:"optimize-multi-agent-v2"`
|
||||
|
||||
@@ -352,10 +352,15 @@ func applyCodexHeadersFromSources(r *http.Request, auth *cliproxyauth.Auth, toke
|
||||
attrs = auth.Attributes
|
||||
}
|
||||
util.ApplyCustomHeadersFromAttrs(r, attrs)
|
||||
if cfg != nil && !cfg.Codex.DisableCodexCloaking {
|
||||
r.Header.Set("User-Agent", codexUserAgent)
|
||||
r.Header.Set("Originator", codexOriginator)
|
||||
applyCodexCloakingHeaders(r.Header, cfg)
|
||||
}
|
||||
|
||||
func applyCodexCloakingHeaders(headers http.Header, cfg *config.Config) {
|
||||
if headers == nil || cfg == nil || cfg.Codex.DisableCodexCloaking {
|
||||
return
|
||||
}
|
||||
headers.Set("User-Agent", codexUserAgent)
|
||||
headers.Set("Originator", codexOriginator)
|
||||
}
|
||||
|
||||
func normalizeCodexInstructions(body []byte) []byte {
|
||||
|
||||
@@ -997,7 +997,63 @@ func TestApplyCodexWebsocketHeadersDefaultsToCurrentResponsesBeta(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCodexWebsocketHeadersPassesThroughClientIdentityHeaders(t *testing.T) {
|
||||
func TestApplyCodexWebsocketHeadersDefaultsToCodexCloaking(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
auth *cliproxyauth.Auth
|
||||
token string
|
||||
}{
|
||||
{
|
||||
name: "OAuth",
|
||||
auth: &cliproxyauth.Auth{
|
||||
Provider: "codex",
|
||||
Attributes: map[string]string{
|
||||
"header:User-Agent": "custom-ua",
|
||||
"header:Originator": "custom-origin",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "API key",
|
||||
auth: &cliproxyauth.Auth{
|
||||
Provider: "codex",
|
||||
Attributes: map[string]string{
|
||||
"api_key": "sk-test",
|
||||
"header:User-Agent": "custom-ua",
|
||||
"header:Originator": "custom-origin",
|
||||
},
|
||||
},
|
||||
token: "sk-test",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
CodexHeaderDefaults: config.CodexHeaderDefaults{UserAgent: "config-ua"},
|
||||
}
|
||||
ctx := contextWithGinHeaders(map[string]string{
|
||||
"User-Agent": "client-ua",
|
||||
"Originator": "client-origin",
|
||||
})
|
||||
headers := http.Header{}
|
||||
headers.Set("User-Agent", "existing-ua")
|
||||
headers.Set("Originator", "existing-origin")
|
||||
|
||||
headers = applyCodexWebsocketHeaders(ctx, headers, tt.auth, tt.token, cfg)
|
||||
|
||||
if got := headers.Get("User-Agent"); got != codexUserAgent {
|
||||
t.Fatalf("User-Agent = %q, want %q", got, codexUserAgent)
|
||||
}
|
||||
if got := headers.Get("Originator"); got != codexOriginator {
|
||||
t.Fatalf("Originator = %q, want %q", got, codexOriginator)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCodexWebsocketHeadersPassesThroughClientIdentityHeadersWhenCloakingDisabled(t *testing.T) {
|
||||
cfg := &config.Config{Codex: config.CodexConfig{DisableCodexCloaking: true}}
|
||||
auth := &cliproxyauth.Auth{
|
||||
Provider: "codex",
|
||||
Metadata: map[string]any{"email": "user@example.com"},
|
||||
@@ -1011,7 +1067,7 @@ func TestApplyCodexWebsocketHeadersPassesThroughClientIdentityHeaders(t *testing
|
||||
"session-id": "legacy-session",
|
||||
})
|
||||
|
||||
headers := applyCodexWebsocketHeaders(ctx, http.Header{}, auth, "", nil)
|
||||
headers := applyCodexWebsocketHeaders(ctx, http.Header{}, auth, "", cfg)
|
||||
|
||||
if got := headers.Get("Originator"); got != "Codex Desktop" {
|
||||
t.Fatalf("Originator = %s, want %s", got, "Codex Desktop")
|
||||
@@ -1059,6 +1115,7 @@ func TestApplyCodexWebsocketHeadersCanonicalizesLegacyUnderscoreSessionHeader(t
|
||||
|
||||
func TestApplyCodexWebsocketHeadersUsesConfigDefaultsForOAuth(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Codex: config.CodexConfig{DisableCodexCloaking: true},
|
||||
CodexHeaderDefaults: config.CodexHeaderDefaults{
|
||||
UserAgent: "my-codex-client/1.0",
|
||||
BetaFeatures: "feature-a,feature-b",
|
||||
@@ -1084,6 +1141,7 @@ func TestApplyCodexWebsocketHeadersUsesConfigDefaultsForOAuth(t *testing.T) {
|
||||
|
||||
func TestApplyCodexWebsocketHeadersPrefersExistingHeadersOverClientAndConfig(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Codex: config.CodexConfig{DisableCodexCloaking: true},
|
||||
CodexHeaderDefaults: config.CodexHeaderDefaults{
|
||||
UserAgent: "config-ua",
|
||||
BetaFeatures: "config-beta",
|
||||
@@ -1113,6 +1171,7 @@ func TestApplyCodexWebsocketHeadersPrefersExistingHeadersOverClientAndConfig(t *
|
||||
|
||||
func TestApplyCodexWebsocketHeadersConfigUserAgentOverridesClientHeader(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Codex: config.CodexConfig{DisableCodexCloaking: true},
|
||||
CodexHeaderDefaults: config.CodexHeaderDefaults{
|
||||
UserAgent: "config-ua",
|
||||
BetaFeatures: "config-beta",
|
||||
@@ -1139,6 +1198,7 @@ func TestApplyCodexWebsocketHeadersConfigUserAgentOverridesClientHeader(t *testi
|
||||
|
||||
func TestApplyCodexWebsocketHeadersIgnoresConfigForAPIKeyAuth(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Codex: config.CodexConfig{DisableCodexCloaking: true},
|
||||
CodexHeaderDefaults: config.CodexHeaderDefaults{
|
||||
UserAgent: "config-ua",
|
||||
BetaFeatures: "config-beta",
|
||||
|
||||
@@ -124,6 +124,7 @@ func applyCodexWebsocketHeaders(ctx context.Context, headers http.Header, auth *
|
||||
attrs = auth.Attributes
|
||||
}
|
||||
util.ApplyCustomHeadersFromAttrs(&http.Request{Header: headers}, attrs)
|
||||
applyCodexCloakingHeaders(headers, cfg)
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user