mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 03:52:26 +08:00
fix(settings): preserve client version on invalid user agent
This commit is contained in:
@@ -394,13 +394,13 @@ func TestGetOpenAICodexCanonicalUserAgentRebuildsPanelUAVersion(t *testing.T) {
|
||||
)
|
||||
})
|
||||
|
||||
// 非 `{client}/{version}` 形态无法重建,原样返回,由收口整体回退规范身份。
|
||||
t.Run("非 Codex 形态原样返回", func(t *testing.T) {
|
||||
// 非 Codex UA 回退到规范身份。
|
||||
t.Run("非 Codex 形态回退", func(t *testing.T) {
|
||||
svc := NewSettingService(&codexVersionSettingRepoStub{values: map[string]string{
|
||||
SettingKeyOpenAICodexUserAgent: "not-a-codex-client",
|
||||
}}, nil)
|
||||
|
||||
require.Equal(t, "not-a-codex-client", svc.GetOpenAICodexCanonicalUserAgent(context.Background()))
|
||||
require.Equal(t, codexCLIUserAgent, svc.GetOpenAICodexCanonicalUserAgent(context.Background()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -478,3 +478,60 @@ func TestCodexVersionComparisonIsNumericNotLexical(t *testing.T) {
|
||||
|
||||
require.Empty(t, repo.syncedWrites(), "0.99.0 低于已同步的 0.146.0,不得写入")
|
||||
}
|
||||
|
||||
func TestGetOpenAICodexCanonicalUserAgentOutboundIdentity(t *testing.T) {
|
||||
codexCanonicalUAMu.RLock()
|
||||
previous := codexCanonicalUAResolver
|
||||
codexCanonicalUAMu.RUnlock()
|
||||
t.Cleanup(func() { SetCodexCanonicalUserAgentResolver(previous) })
|
||||
|
||||
for _, version := range []struct {
|
||||
name, manual, synced, want string
|
||||
}{
|
||||
{"manual", "0.154.0", "0.155.1", "0.154.0"},
|
||||
{"synced", "", "0.155.1", "0.155.1"},
|
||||
{"invalid_manual", "latest", "0.155.1", "0.155.1"},
|
||||
{"default", "", "", codexCLIVersion},
|
||||
{"invalid_versions", "latest", "invalid", codexCLIVersion},
|
||||
} {
|
||||
for _, ua := range []struct {
|
||||
name, value, client, suffix string
|
||||
}{
|
||||
{name: "browser", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"},
|
||||
{name: "arbitrary", value: "not-a-codex-client"},
|
||||
{name: "unknown_client", value: "custom/0.140.0 (Linux)"},
|
||||
{name: "empty"},
|
||||
{name: "missing_version", value: "codex_cli_rs/"},
|
||||
{name: "crlf", value: "codex_cli_rs/0.140.0 (Linux)\r\nX-Injected: value"},
|
||||
{name: "nul", value: "codex_cli_rs/0.140.0 (Linux\x00)"},
|
||||
{name: "del", value: "codex_cli_rs/0.140.0 terminal\x7f"},
|
||||
{name: "leading_newline", value: "\ncodex_cli_rs/0.140.0 (Linux)"},
|
||||
{name: "trailing_newline", value: "codex_cli_rs/0.140.0 (Linux)\n"},
|
||||
{name: "valid_suffix", value: "codex_cli_rs/0.140.0 (Mac OS X 15.1.0; arm64) iTerm.app", client: "codex_cli_rs", suffix: " (Mac OS X 15.1.0; arm64) iTerm.app"},
|
||||
{name: "valid_tab", value: "codex_cli_rs/0.140.0 (Linux)\tterminal", client: "codex_cli_rs", suffix: " (Linux)\tterminal"},
|
||||
{name: "recognized_trailer", value: "custom/0.140.0 (Linux) (codex-tui; 0.140.0)", client: "codex-tui", suffix: " (Linux) (codex-tui; " + version.want + ")"},
|
||||
} {
|
||||
t.Run(version.name+"/"+ua.name, func(t *testing.T) {
|
||||
svc := NewSettingService(&codexVersionSettingRepoStub{values: map[string]string{
|
||||
SettingKeyOpenAICodexUserAgent: ua.value,
|
||||
SettingKeyOpenAICodexClientVersion: version.manual,
|
||||
SettingKeyOpenAICodexClientVersionSynced: version.synced,
|
||||
}}, nil)
|
||||
wantUA := buildCodexCLIUserAgent(version.want)
|
||||
wantOriginator := "codex-tui"
|
||||
if ua.client != "" {
|
||||
wantUA = ua.client + "/" + version.want + ua.suffix
|
||||
wantOriginator = ua.client
|
||||
}
|
||||
SetCodexCanonicalUserAgentResolver(func() string {
|
||||
return svc.GetOpenAICodexCanonicalUserAgent(context.Background())
|
||||
})
|
||||
require.Equal(t, wantUA, svc.GetOpenAICodexCanonicalUserAgent(context.Background()))
|
||||
identity := resolveCodexOutboundIdentity("")
|
||||
require.Equal(t, wantUA, identity.userAgent)
|
||||
require.Equal(t, wantOriginator, identity.originator)
|
||||
require.Equal(t, version.want, identity.version)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,8 @@ func (s *SettingService) GetOpenAICodexUserAgent(ctx context.Context) string {
|
||||
})
|
||||
return fallback, nil
|
||||
}
|
||||
ua := strings.TrimSpace(value)
|
||||
// Preserve invalid header bytes for canonical identity validation.
|
||||
ua := strings.Trim(value, " \t")
|
||||
if ua == "" {
|
||||
ua = fallback
|
||||
}
|
||||
@@ -389,16 +390,14 @@ func (s *SettingService) GetOpenAICodexCanonicalUserAgent(ctx context.Context) s
|
||||
return codexCLIUserAgent
|
||||
}
|
||||
version := s.GetOpenAICodexClientVersion(ctx)
|
||||
ua := strings.TrimSpace(s.GetOpenAICodexUserAgent(ctx))
|
||||
if ua == "" {
|
||||
return buildCodexCLIUserAgent(version)
|
||||
ua := s.GetOpenAICodexUserAgent(ctx)
|
||||
if _, pairedUA, ok := openai.PairCodexClientIdentity(ua); ok {
|
||||
if rebuilt := openai.SetCodexUserAgentVersion(pairedUA, version); rebuilt != "" {
|
||||
return rebuilt
|
||||
}
|
||||
}
|
||||
if rebuilt := openai.SetCodexUserAgentVersion(ua, version); rebuilt != "" {
|
||||
return rebuilt
|
||||
}
|
||||
// 非 `{client}/{version}` 形态:交给 PairCodexClientIdentity 判定,
|
||||
// 推导不出官方身份时由收口整体回退规范身份。
|
||||
return ua
|
||||
// Invalid fingerprints must not discard the independently resolved version.
|
||||
return buildCodexCLIUserAgent(version)
|
||||
}
|
||||
|
||||
var legacyClaudeCodeCodexWhitelistEntry = openai.AllowedClientEntry{
|
||||
|
||||
Reference in New Issue
Block a user