mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-02 00:30:32 +00:00
feat(codex-detect): codex_cli_only 检测加固 + 引擎指纹统一信号列表 + 账号级 app-server
将 codex_cli_only 客户端识别从「单一 strict 开关 + 固定 OR 头集合」重构为 可逐项管理的引擎指纹信号列表,加固整条判定链,并补齐账号级 app-server 控制、 对齐前端设置文案。 判定链(每步可短路): - 账号未开 codex_cli_only → 不限制;gateway.force_codex_cli → 旁路放行 - 全局黑名单命中(OR 宽 deny)→ 立即拒 - 身份候选:官方 UA(strict,仅前缀)/ 官方 originator(OR)/ 全局白名单(双因子 AND) / 全局 app-server 开关 OR 账号 app-server 开关;均不命中 → 拒 - 版本门(仅官方候选):UA 须可解析引擎版本,再校验 [min,max] 区间 - 引擎指纹 AND 硬门:按信号列表逐条勾选 AND、每条行内变体 OR;无 Required 信号 → 放行 引擎指纹信号列表(唯一真源) - 新增 openai.EngineFingerprintSignal 类型 + EvaluateEngineFingerprint 求值器 (勾选 AND / 行内变体 OR / 无勾选 → 放行) - CodexRestrictionPolicy 增 EngineFingerprintSignals;信号列表单一决定是否启用指纹门, 不再保留独立「要求引擎指纹」总开关(与「信号全不选」语义重复) - 新设置键 codex_cli_only_engine_fingerprint_signals(默认只勾 x-codex- 前缀); 旧 body 指纹开关幂等迁移并入信号列表;wire 接线 - 黑/白名单自由条目、命名预设、版本区间 全局设置管线 - gateway 缺 settingService(仅测试/误配可达)时指纹门回退默认种子信号、失败关闭, 不再因零值 policy(nil 信号)失败开放 账号级 Codex app-server(替换已失效的 ClaudeCode 放行机制) - account.IsCodexCLIOnlyAppServerAllowed() 读 extra.codex_cli_only_allow_app_server, 仅在 codex_cli_only 开启时生效;候选身份门「全局 OR 账号」,与旧系统双层控制对齐 - 移除已无入口的 claude_code 预设机制(allowedClientRegistry / MatchAllowedClients / 账号 GetCodexCLIOnlyAllowedClients / reason);白名单 AllowedClientEntry / IsAllowedClientMatch 保留 门加固(反伪 + 写入校验) - 官方 UA 访问门改 strict:IsCodexOfficialClientRequestStrict 仅前缀匹配,收窄「浏览器前缀 + 中段 codex token」伪造面(strict 仍保留 Codex 家族前缀与 UA 尾部兜底,故对「任意前缀 + 官方尾部 (name;ver)」仍放行——与 UA 可伪造、真正反伪靠引擎指纹门的设计一致) - 官方客户端识别扩展:新增 codex-tui/、codex_vscode_copilot/ 前缀 + UA 尾部 (name;ver) 兜底 (恢复 CODEX_INTERNAL_ORIGINATOR_OVERRIDE 的真实 client,如 cccc→codex-tui),originator 改 精确集。该识别经 IsCodexOfficialClientByHeaders 被 passthrough 复用,故透传的官方判定一并 修正(codex-tui 等不再被误改写 UA)——非「行为不变」,属有意修正 - 白名单写入校验 ValidateCodexWhitelistEntriesJSON + AllowedClientEntry.IsWhitelistable: 双因子 AND 条目须可命中(非空 originator + 非空 ua_contains),拒绝写入会静默失效的死规则; 黑名单(OR 宽 deny,允许 originator-only)不受约束 管理端 / 前端 - handler / DTO / settings_view / 契约测试;gateway 接入判定链 - 信号列表编辑器(替换 body 开关)、api 类型、SettingsView;无勾选给常驻警告 - Create/Edit/Bulk 三弹窗「Codex Only」下新增 app-server 开关(OR 合并全局) - 文案:UA/Originator → User-Agent/Originator;黑/白名单重命名为 User-Agent/Originator 黑/白名单; 「允许 App Server 第三方客户端」→「Codex app-server」+ 简介示例;i18n zh/en 同步 - 移除死代码 HasCodex*Fingerprint helper 测试:引擎指纹求值器 / 账号 app-server(OR 语义)/ detector(含 N1 strict、失败关闭)/ 白名单写入校验 / BulkEdit spec 等;后端 build + service/openai/admin 单测全绿,前端 vue-tsc + vitest 全绿。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f93a6c50ce
commit
819fda34d9
@@ -3461,9 +3461,9 @@ export default {
|
||||
codexCLIOnly: 'Codex official clients only',
|
||||
codexCLIOnlyDesc:
|
||||
'Only applies to OpenAI OAuth. When enabled, only Codex official client families are allowed; when disabled, the gateway bypasses this restriction and keeps existing behavior.',
|
||||
codexCLIOnlyAllowClaudeCode: "Also allow Claude Code's Codex plugin",
|
||||
codexCLIOnlyAllowClaudeCodeDesc:
|
||||
'Only takes effect when the switch above is on. Additionally allows requests from the Claude Code Codex plugin (exact match on originator=Claude Code) without weakening blocking of other non-official clients.',
|
||||
codexCLIOnlyAppServer: 'Allow Codex app-server clients',
|
||||
codexCLIOnlyAppServerDesc:
|
||||
"Effective only when the switch above is on. When enabled, this account also allows third-party clients that embed the Codex engine over the app-server protocol (e.g. Claude Code's codex plugin); they still pass the global engine-fingerprint gate. OR-combined with the global app-server toggle.",
|
||||
codexImageGenerationBridge: 'Codex image-generation bridge',
|
||||
codexImageGenerationBridgeDesc:
|
||||
'Account policy takes precedence over channel and global settings. Only controls whether Codex requests through the /responses text endpoint receive the image_generation tool; standalone image-generation endpoints are unaffected.',
|
||||
@@ -5830,9 +5830,41 @@ export default {
|
||||
openaiCodexUserAgent: 'OpenAI Codex UA',
|
||||
openaiCodexUserAgentPlaceholder: 'codex-tui/0.125.0 (Ubuntu 22.4.0; x86_64) xterm-256color (codex-tui; 0.125.0)',
|
||||
openaiCodexUserAgentHint: 'Used to bypass Cloudflare browser-UA challenges on the OpenAI upstream. Only applies when the client User-Agent is detected as a browser (Mozilla/...). Leave empty to use the built-in default.',
|
||||
openaiAllowClaudeCodeCodexPlugin: "Allow using the Codex plugin in Claude Code",
|
||||
openaiAllowClaudeCodeCodexPluginDesc:
|
||||
"Global switch; only affects OpenAI OAuth accounts that have 'Codex official clients only' enabled. When on, all such accounts additionally allow requests from the Claude Code Codex plugin (exact match on originator=Claude Code) without per-account config; upstream requests remain pass-through.",
|
||||
codexHardeningTitle: "Codex Settings",
|
||||
codexClientRestrictionTitle: "Codex client restriction",
|
||||
codexHardeningDesc:
|
||||
"Only affects OpenAI OAuth accounts with 'Codex official clients only' enabled (global). Beyond User-Agent/Originator, harden the decision with a version range, an engine-fingerprint gate, and black/whitelists.",
|
||||
minCodexVersion: "Min Codex Version",
|
||||
minCodexVersionPlaceholder: "e.g. 0.142.0",
|
||||
maxCodexVersion: "Max Codex Version",
|
||||
maxCodexVersionPlaceholder: "e.g. 0.200.0",
|
||||
codexVersionHint:
|
||||
"Official clients only: checks their version against the [min, max] range. Leave a side empty to not limit it.",
|
||||
codexFingerprintSignals: "Codex engine fingerprint signals",
|
||||
codexFingerprintSignalsDesc:
|
||||
"Define engine-fingerprint signals: every Required signal must match (AND); within a row, '/'-separated variants are OR'd. None checked = not enforced. Default checks only the x-codex- prefix. Types: header exact / header prefix / body path.",
|
||||
codexFpTypeHeaderExact: "Header exact",
|
||||
codexFpTypeHeaderPrefix: "Header prefix",
|
||||
codexFpTypeBodyPath: "Body path",
|
||||
codexFpMatchPlaceholder: "match; '/'-separate variants (e.g. session-id / session_id or x-codex-)",
|
||||
codexFpRequired: "Required",
|
||||
codexFingerprintNoRequiredWarn: "No signal is marked Required — the engine-fingerprint gate is inactive, allowing every candidate that passes identity/version. Check at least one signal to enable it.",
|
||||
codexAllowAppServer: "Codex app-server",
|
||||
codexAllowAppServerDesc:
|
||||
"Allow third-party clients that embed the Codex engine and connect over the app-server protocol (e.g. Claude Code's codex plugin). Off by default; when on, such clients are allowed once they pass the engine-fingerprint gate (the signal list below); off = only official clients and the whitelist are allowed.",
|
||||
codexBlacklist: "User-Agent/Originator Blacklist",
|
||||
codexBlacklistDesc:
|
||||
"Deny if any field matches; takes precedence over any allow. originator is exact; User-Agent is a 'contains' match (comma-separated).",
|
||||
codexWhitelist: "User-Agent/Originator Whitelist",
|
||||
codexWhitelistDesc:
|
||||
"Allow clients outside the official set: requires exact originator and every User-Agent marker present. Still subject to the fingerprint gate unless 'Skip engine fingerprint' is checked.",
|
||||
codexWhitelistSkipFingerprint: "Skip engine fingerprint",
|
||||
codexWhitelistSkipFingerprintTooltip:
|
||||
"Risk: when checked this entry is allowed on originator + User-Agent alone (both forgeable), with no engine-fingerprint backstop. Use only for trusted third-party clients that genuinely do not send a codex engine fingerprint.",
|
||||
codexOriginatorPlaceholder: "originator (exact, e.g. opencode)",
|
||||
codexUaContainsPlaceholder: "User-Agent contains markers, comma-separated (e.g. opencode/)",
|
||||
codexAddRow: "Add entry",
|
||||
codexRemoveRow: "Remove",
|
||||
},
|
||||
webSearchEmulation: {
|
||||
title: 'Web Search Emulation',
|
||||
|
||||
@@ -3630,8 +3630,8 @@ export default {
|
||||
responsesStatusForcedChatCompletions: '已强制 Chat Completions',
|
||||
codexCLIOnly: '仅允许 Codex 官方客户端',
|
||||
codexCLIOnlyDesc: '仅对 OpenAI OAuth 生效。开启后仅允许 Codex 官方客户端家族访问;关闭后完全绕过并保持原逻辑。',
|
||||
codexCLIOnlyAllowClaudeCode: '额外放行 Claude Code 的 Codex 插件',
|
||||
codexCLIOnlyAllowClaudeCodeDesc: '仅在上方开关开启时生效。额外放行通过 Claude Code 的 Codex 插件发起的请求(精确匹配 originator=Claude Code),不影响对其他非官方客户端的拦截。',
|
||||
codexCLIOnlyAppServer: '允许 Codex app-server 客户端',
|
||||
codexCLIOnlyAppServerDesc: '仅在上方开关开启时生效。开启后本账号额外放行内嵌 Codex 引擎、经 app-server 协议接入的第三方客户端(如 Claude Code 的 codex 插件),仍需通过全局引擎指纹门;与全局 app-server 开关取 OR(任一开即放行)。',
|
||||
codexImageGenerationBridge: 'Codex 图片生成桥接',
|
||||
codexImageGenerationBridgeDesc:
|
||||
'账号级策略优先于渠道和全局配置。仅控制 Codex 走 /responses 文本端点时是否注入 image_generation 工具;不影响独立图片生成接口。',
|
||||
@@ -5984,9 +5984,41 @@ export default {
|
||||
openaiCodexUserAgent: 'OpenAI Codex UA',
|
||||
openaiCodexUserAgentPlaceholder: 'codex-tui/0.125.0 (Ubuntu 22.4.0; x86_64) xterm-256color (codex-tui; 0.125.0)',
|
||||
openaiCodexUserAgentHint: '用于规避 OpenAI 上游 Cloudflare 对浏览器 UA 的访问质询。仅在检测到客户端 User-Agent 为浏览器(Mozilla/...)时生效,其他客户端原样透传。留空使用内置默认值。',
|
||||
openaiAllowClaudeCodeCodexPlugin: '允许在 Claude Code 中使用 Codex 插件',
|
||||
openaiAllowClaudeCodeCodexPluginDesc:
|
||||
'全局开关,仅对已开启「仅允许 Codex 官方客户端」的 OpenAI OAuth 账号生效。开启后,所有此类账号都额外放行通过 Claude Code 的 Codex 插件发起的请求(精确匹配 originator=Claude Code),无需逐账号配置;上游请求仍保持透传。',
|
||||
codexHardeningTitle: 'Codex 设置',
|
||||
codexClientRestrictionTitle: 'Codex 客户端限制',
|
||||
codexHardeningDesc:
|
||||
'仅对已开启「仅允许 Codex 官方客户端」的 OpenAI OAuth 账号生效(全局)。在 User-Agent/Originator 之外,用版本区间、引擎指纹门与黑/白名单巩固判定。',
|
||||
minCodexVersion: '最低 Codex 版本',
|
||||
minCodexVersionPlaceholder: '例如 0.142.0',
|
||||
maxCodexVersion: '最高 Codex 版本',
|
||||
maxCodexVersionPlaceholder: '例如 0.200.0',
|
||||
codexVersionHint:
|
||||
'仅对官方客户端生效,校验其版本是否落在 [最低, 最高] 区间。留空表示该侧不限制。',
|
||||
codexFingerprintSignals: 'Codex 引擎指纹信号',
|
||||
codexFingerprintSignalsDesc:
|
||||
'定义引擎指纹信号:勾「必须」的信号需全部命中(AND),每条 / 分隔的变体取或(OR);一条都不勾即不校验。默认只勾 x-codex- 前缀。类型:头精确 / 头前缀 / body 路径。',
|
||||
codexFpTypeHeaderExact: '头精确',
|
||||
codexFpTypeHeaderPrefix: '头前缀',
|
||||
codexFpTypeBodyPath: 'body 路径',
|
||||
codexFpMatchPlaceholder: '匹配,变体用 / 分隔(如 session-id / session_id 或 x-codex-)',
|
||||
codexFpRequired: '必须',
|
||||
codexFingerprintNoRequiredWarn: '未勾选任何「必须」信号——引擎指纹门当前不生效,等于放行所有通过身份/版本的候选。如需启用校验,请至少勾选一条信号。',
|
||||
codexAllowAppServer: 'Codex app-server',
|
||||
codexAllowAppServerDesc:
|
||||
'放行内嵌 Codex 引擎、经 app-server 协议接入的第三方客户端(如 Claude Code 的 codex 插件)。默认关闭;开启后此类客户端通过引擎指纹门(下方信号列表)即放行,关闭则仅放行官方客户端与白名单。',
|
||||
codexBlacklist: 'User-Agent/Originator 黑名单',
|
||||
codexBlacklistDesc:
|
||||
'命中任一字段即拒,优先于一切放行。originator 精确匹配,User-Agent 为包含匹配(多个用逗号分隔)。',
|
||||
codexWhitelist: 'User-Agent/Originator 白名单',
|
||||
codexWhitelistDesc:
|
||||
'放行官方集之外的客户端:需 originator 精确,且每个 User-Agent 标记都命中。默认仍需过引擎指纹门,勾「跳过引擎指纹」可免。',
|
||||
codexWhitelistSkipFingerprint: '跳过引擎指纹',
|
||||
codexWhitelistSkipFingerprintTooltip:
|
||||
'风险:勾选后该条仅凭 originator + User-Agent(均可伪造)放行,不再要求引擎指纹兜底。仅用于确属可信、但本身不发 codex 引擎指纹的第三方客户端。',
|
||||
codexOriginatorPlaceholder: 'originator(精确,如 opencode)',
|
||||
codexUaContainsPlaceholder: 'User-Agent 包含标记,逗号分隔(如 opencode/)',
|
||||
codexAddRow: '添加一条',
|
||||
codexRemoveRow: '删除',
|
||||
},
|
||||
webSearchEmulation: {
|
||||
title: 'Web Search 模拟',
|
||||
|
||||
Reference in New Issue
Block a user