/** * Claude Code Headers 管理服务 * 负责存储和管理不同账号使用的 Claude Code headers */ const redis = require('../models/redis'); const logger = require('../utils/logger'); class ClaudeCodeHeadersService { constructor() { this.defaultHeaders = { 'x-stainless-retry-count': '0', 'x-stainless-timeout': '60', 'x-stainless-lang': 'js', 'x-stainless-package-version': '0.55.1', 'x-stainless-os': 'Windows', 'x-stainless-arch': 'x64', 'x-stainless-runtime': 'node', 'x-stainless-runtime-version': 'v20.19.2', 'anthropic-dangerous-direct-browser-access': 'true', 'x-app': 'cli', 'user-agent': 'claude-cli/1.0.57 (external, cli)', 'accept-language': '*', 'sec-fetch-mode': 'cors' }; // 需要捕获的 Claude Code 特定 headers this.claudeCodeHeaderKeys = [ 'x-stainless-retry-count', 'x-stainless-timeout', 'x-stainless-lang', 'x-stainless-package-version', 'x-stainless-os', 'x-stainless-arch', 'x-stainless-runtime', 'x-stainless-runtime-version', 'anthropic-dangerous-direct-browser-access', 'x-app', 'user-agent', 'accept-language', 'sec-fetch-mode', 'accept-encoding' ]; } /** * 从 user-agent 中提取版本号 */ extractVersionFromUserAgent(userAgent) { if (!userAgent) return null; const match = userAgent.match(/claude-cli\/(\d+\.\d+\.\d+)/); return match ? match[1] : null; } /** * 比较版本号 * @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal */ compareVersions(v1, v2) { if (!v1 || !v2) return 0; 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 p1 = parts1[i] || 0; const p2 = parts2[i] || 0; if (p1 > p2) return 1; if (p1 < p2) return -1; } return 0; } /** * 从客户端 headers 中提取 Claude Code 相关的 headers */ extractClaudeCodeHeaders(clientHeaders) { const headers = {}; // 转换所有 header keys 为小写进行比较 const lowerCaseHeaders = {}; Object.keys(clientHeaders || {}).forEach(key => { lowerCaseHeaders[key.toLowerCase()] = clientHeaders[key]; }); // 提取需要的 headers this.claudeCodeHeaderKeys.forEach(key => { const lowerKey = key.toLowerCase(); if (lowerCaseHeaders[lowerKey]) { headers[key] = lowerCaseHeaders[lowerKey]; } }); return headers; } /** * 存储账号的 Claude Code headers */ async storeAccountHeaders(accountId, clientHeaders) { try { const extractedHeaders = this.extractClaudeCodeHeaders(clientHeaders); // 检查是否有 user-agent const userAgent = extractedHeaders['user-agent']; if (!userAgent || !userAgent.includes('claude-cli')) { // 不是 Claude Code 的请求,不存储 return; } const version = this.extractVersionFromUserAgent(userAgent); if (!version) { logger.warn(`⚠️ Failed to extract version from user-agent: ${userAgent}`); return; } // 获取当前存储的 headers const key = `claude_code_headers:${accountId}`; const currentData = await redis.getClient().get(key); if (currentData) { const current = JSON.parse(currentData); const currentVersion = this.extractVersionFromUserAgent(current.headers['user-agent']); // 只有新版本更高时才更新 if (this.compareVersions(version, currentVersion) <= 0) { return; } } // 存储新的 headers const data = { headers: extractedHeaders, version: version, updatedAt: new Date().toISOString() }; await redis.getClient().setex(key, 86400 * 7, JSON.stringify(data)); // 7天过期 logger.info(`✅ Stored Claude Code headers for account ${accountId}, version: ${version}`); } catch (error) { logger.error(`❌ Failed to store Claude Code headers for account ${accountId}:`, error); } } /** * 获取账号的 Claude Code headers */ async getAccountHeaders(accountId) { try { const key = `claude_code_headers:${accountId}`; const data = await redis.getClient().get(key); if (data) { const parsed = JSON.parse(data); logger.debug(`📋 Retrieved Claude Code headers for account ${accountId}, version: ${parsed.version}`); return parsed.headers; } // 返回默认 headers logger.debug(`📋 Using default Claude Code headers for account ${accountId}`); return this.defaultHeaders; } catch (error) { logger.error(`❌ Failed to get Claude Code headers for account ${accountId}:`, error); return this.defaultHeaders; } } /** * 清除账号的 Claude Code headers */ async clearAccountHeaders(accountId) { try { const key = `claude_code_headers:${accountId}`; await redis.getClient().del(key); logger.info(`🗑️ Cleared Claude Code headers for account ${accountId}`); } catch (error) { logger.error(`❌ Failed to clear Claude Code headers for account ${accountId}:`, error); } } /** * 获取所有账号的 headers 信息 */ async getAllAccountHeaders() { try { const pattern = 'claude_code_headers:*'; const keys = await redis.getClient().keys(pattern); const results = {}; for (const key of keys) { const accountId = key.replace('claude_code_headers:', ''); const data = await redis.getClient().get(key); if (data) { results[accountId] = JSON.parse(data); } } return results; } catch (error) { logger.error('❌ Failed to get all account headers:', error); return {}; } } } module.exports = new ClaudeCodeHeadersService();