|
|
const logger = require('../../utils/logger') |
|
|
const { CLIENT_DEFINITIONS } = require('../clientDefinitions') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CodexCliValidator { |
|
|
|
|
|
|
|
|
|
|
|
static getId() { |
|
|
return CLIENT_DEFINITIONS.CODEX_CLI.id |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static getName() { |
|
|
return CLIENT_DEFINITIONS.CODEX_CLI.name |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static getDescription() { |
|
|
return CLIENT_DEFINITIONS.CODEX_CLI.description |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static validate(req) { |
|
|
try { |
|
|
const userAgent = req.headers['user-agent'] || '' |
|
|
const originator = req.headers['originator'] || '' |
|
|
const sessionId = req.headers['session_id'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const strictValidationPaths = ['/openai', '/azure'] |
|
|
const needsStrictValidation = |
|
|
req.path && strictValidationPaths.some((path) => req.path.startsWith(path)) |
|
|
|
|
|
if (!needsStrictValidation) { |
|
|
|
|
|
logger.debug(`Codex CLI detected for path: ${req.path}, allowing access`) |
|
|
return true |
|
|
} |
|
|
|
|
|
|
|
|
const clientType = uaMatch[1].toLowerCase() |
|
|
if (originator.toLowerCase() !== clientType) { |
|
|
logger.debug( |
|
|
`Codex CLI validation failed - originator mismatch. UA: ${clientType}, originator: ${originator}` |
|
|
) |
|
|
return false |
|
|
} |
|
|
|
|
|
|
|
|
if (!sessionId || sessionId.length <= 20) { |
|
|
logger.debug(`Codex CLI validation failed - session_id missing or too short: ${sessionId}`) |
|
|
return false |
|
|
} |
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|