mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
fix:修复1.1.147版本启动问题
This commit is contained in:
147
src/validators/clients/codexCliValidator.js
Normal file
147
src/validators/clients/codexCliValidator.js
Normal file
@@ -0,0 +1,147 @@
|
||||
const logger = require('../../utils/logger')
|
||||
const { CLIENT_DEFINITIONS } = require('../clientDefinitions')
|
||||
|
||||
/**
|
||||
* Codex CLI 验证器
|
||||
* 验证请求是否来自 Codex CLI
|
||||
*/
|
||||
class CodexCliValidator {
|
||||
/**
|
||||
* 获取客户端ID
|
||||
*/
|
||||
static getId() {
|
||||
return CLIENT_DEFINITIONS.CODEX_CLI.id
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端名称
|
||||
*/
|
||||
static getName() {
|
||||
return CLIENT_DEFINITIONS.CODEX_CLI.name
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端描述
|
||||
*/
|
||||
static getDescription() {
|
||||
return CLIENT_DEFINITIONS.CODEX_CLI.description
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证请求是否来自 Codex CLI
|
||||
* @param {Object} req - Express 请求对象
|
||||
* @returns {boolean} 验证结果
|
||||
*/
|
||||
static validate(req) {
|
||||
try {
|
||||
const userAgent = req.headers['user-agent'] || ''
|
||||
const originator = req.headers['originator'] || ''
|
||||
const sessionId = req.headers['session_id']
|
||||
|
||||
// 1. 基础 User-Agent 检查
|
||||
// Codex CLI 的 UA 格式:
|
||||
// - codex_vscode/0.35.0 (Windows 10.0.26100; x86_64) unknown (Cursor; 0.4.10)
|
||||
// - codex_cli_rs/0.38.0 (Ubuntu 22.4.0; x86_64) WindowsTerminal
|
||||
const codexCliPattern = /^(codex_vscode|codex_cli_rs)\/[\d\.]+/i
|
||||
const uaMatch = userAgent.match(codexCliPattern)
|
||||
|
||||
if (!uaMatch) {
|
||||
logger.debug(`Codex CLI validation failed - UA mismatch: ${userAgent}`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 2. 对于特定路径,进行额外的严格验证
|
||||
// 对于 /openai 和 /azure 路径需要完整验证
|
||||
const strictValidationPaths = ['/openai', '/azure']
|
||||
const needsStrictValidation = req.path && strictValidationPaths.some(path => req.path.startsWith(path))
|
||||
|
||||
if (!needsStrictValidation) {
|
||||
// 其他路径,只要 User-Agent 匹配就认为是 Codex CLI
|
||||
logger.debug(`Codex CLI detected for path: ${req.path}, allowing access`)
|
||||
return true
|
||||
}
|
||||
|
||||
// 3. 验证 originator 头必须与 UA 中的客户端类型匹配
|
||||
const clientType = uaMatch[1].toLowerCase()
|
||||
if (originator.toLowerCase() !== clientType) {
|
||||
logger.debug(
|
||||
`Codex CLI validation failed - originator mismatch. UA: ${clientType}, originator: ${originator}`
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
// 4. 检查 session_id - 必须存在且长度大于20
|
||||
if (!sessionId || sessionId.length <= 20) {
|
||||
logger.debug(`Codex CLI validation failed - session_id missing or too short: ${sessionId}`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 5. 对于 /openai/responses 和 /azure/response 路径,额外检查 body 中的 instructions 字段
|
||||
if (
|
||||
req.path &&
|
||||
(req.path.includes('/openai/responses') || req.path.includes('/azure/response'))
|
||||
) {
|
||||
if (!req.body || !req.body.instructions) {
|
||||
logger.debug(`Codex CLI validation failed - missing instructions in body for ${req.path}`)
|
||||
return false
|
||||
}
|
||||
|
||||
const expectedPrefix =
|
||||
'You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI'
|
||||
if (!req.body.instructions.startsWith(expectedPrefix)) {
|
||||
logger.debug(`Codex CLI validation failed - invalid instructions prefix for ${req.path}`)
|
||||
logger.debug(`Expected: "${expectedPrefix}..."`)
|
||||
logger.debug(`Received: "${req.body.instructions.substring(0, 100)}..."`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 额外检查 model 字段应该是 gpt-5-codex
|
||||
if (req.body.model && req.body.model !== 'gpt-5-codex') {
|
||||
logger.debug(`Codex CLI validation warning - unexpected model: ${req.body.model}`)
|
||||
// 只记录警告,不拒绝请求
|
||||
}
|
||||
}
|
||||
|
||||
// 所有必要检查通过
|
||||
logger.debug(`Codex CLI validation passed for UA: ${userAgent}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
logger.error('Error in CodexCliValidator:', error)
|
||||
// 验证出错时默认拒绝
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较版本号
|
||||
* @returns {number} -1: v1 < v2, 0: v1 = v2, 1: v1 > v2
|
||||
*/
|
||||
static compareVersions(v1, v2) {
|
||||
const parts1 = v1.split('.').map(Number)
|
||||
const parts2 = v2.split('.').map(Number)
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const part1 = parts1[i] || 0
|
||||
const part2 = parts2[i] || 0
|
||||
|
||||
if (part1 < part2) return -1
|
||||
if (part1 > part2) return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证器信息
|
||||
*/
|
||||
static getInfo() {
|
||||
return {
|
||||
id: this.getId(),
|
||||
name: this.getName(),
|
||||
description: this.getDescription(),
|
||||
icon: CLIENT_DEFINITIONS.CODEX_CLI.icon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CodexCliValidator
|
||||
Reference in New Issue
Block a user