feat: 适配新版本gemini

This commit is contained in:
shaw
2025-10-14 11:24:27 +08:00
parent 46ba514801
commit d6a9beff2f
4 changed files with 84 additions and 23 deletions

View File

@@ -65,6 +65,44 @@ const TOKEN_COUNT_PATHS = new Set([
'/droid/claude/v1/messages/count_tokens' '/droid/claude/v1/messages/count_tokens'
]) ])
function extractApiKey(req) {
const candidates = [
req.headers['x-api-key'],
req.headers['x-goog-api-key'],
req.headers['authorization'],
req.headers['api-key'],
req.query?.key
]
for (const candidate of candidates) {
let value = candidate
if (Array.isArray(value)) {
value = value.find((item) => typeof item === 'string' && item.trim())
}
if (typeof value !== 'string') {
continue
}
let trimmed = value.trim()
if (!trimmed) {
continue
}
if (/^Bearer\s+/i.test(trimmed)) {
trimmed = trimmed.replace(/^Bearer\s+/i, '').trim()
if (!trimmed) {
continue
}
}
return trimmed
}
return ''
}
function normalizeRequestPath(value) { function normalizeRequestPath(value) {
if (!value) { if (!value) {
return '/' return '/'
@@ -95,18 +133,18 @@ const authenticateApiKey = async (req, res, next) => {
try { try {
// 安全提取API Key支持多种格式包括Gemini CLI支持 // 安全提取API Key支持多种格式包括Gemini CLI支持
const apiKey = const apiKey = extractApiKey(req)
req.headers['x-api-key'] ||
req.headers['x-goog-api-key'] || if (apiKey) {
req.headers['authorization']?.replace(/^Bearer\s+/i, '') || req.headers['x-api-key'] = apiKey
req.headers['api-key'] || }
req.query.key
if (!apiKey) { if (!apiKey) {
logger.security(`🔒 Missing API key attempt from ${req.ip || 'unknown'}`) logger.security(`🔒 Missing API key attempt from ${req.ip || 'unknown'}`)
return res.status(401).json({ return res.status(401).json({
error: 'Missing API key', error: 'Missing API key',
message: 'Please provide an API key in the x-api-key header or Authorization header' message:
'Please provide an API key in the x-api-key, x-goog-api-key, or Authorization header'
}) })
} }
@@ -950,6 +988,7 @@ const corsMiddleware = (req, res, next) => {
'Accept', 'Accept',
'Authorization', 'Authorization',
'x-api-key', 'x-api-key',
'x-goog-api-key',
'api-key', 'api-key',
'x-admin-token', 'x-admin-token',
'anthropic-version', 'anthropic-version',

View File

@@ -7,12 +7,38 @@ const logger = require('../utils/logger')
const browserFallbackMiddleware = (req, res, next) => { const browserFallbackMiddleware = (req, res, next) => {
const userAgent = req.headers['user-agent'] || '' const userAgent = req.headers['user-agent'] || ''
const origin = req.headers['origin'] || '' const origin = req.headers['origin'] || ''
const authHeader = req.headers['authorization'] || req.headers['x-api-key'] || ''
const extractHeader = (value) => {
let candidate = value
if (Array.isArray(candidate)) {
candidate = candidate.find((item) => typeof item === 'string' && item.trim())
}
if (typeof candidate !== 'string') {
return ''
}
let trimmed = candidate.trim()
if (!trimmed) {
return ''
}
if (/^Bearer\s+/i.test(trimmed)) {
trimmed = trimmed.replace(/^Bearer\s+/i, '').trim()
}
return trimmed
}
const apiKeyHeader =
extractHeader(req.headers['x-api-key']) || extractHeader(req.headers['x-goog-api-key'])
const normalizedKey = extractHeader(req.headers['authorization']) || apiKeyHeader
// 检查是否为Chrome插件或浏览器请求 // 检查是否为Chrome插件或浏览器请求
const isChromeExtension = origin.startsWith('chrome-extension://') const isChromeExtension = origin.startsWith('chrome-extension://')
const isBrowserRequest = userAgent.includes('Mozilla/') && userAgent.includes('Chrome/') const isBrowserRequest = userAgent.includes('Mozilla/') && userAgent.includes('Chrome/')
const hasApiKey = authHeader.startsWith('cr_') // 我们的API Key格式 const hasApiKey = normalizedKey.startsWith('cr_') // 我们的API Key格式
if ((isChromeExtension || isBrowserRequest) && hasApiKey) { if ((isChromeExtension || isBrowserRequest) && hasApiKey) {
// 为Chrome插件请求添加特殊标记 // 为Chrome插件请求添加特殊标记
@@ -23,8 +49,8 @@ const browserFallbackMiddleware = (req, res, next) => {
req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)' req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)'
// 确保设置正确的认证头 // 确保设置正确的认证头
if (!req.headers['authorization'] && req.headers['x-api-key']) { if (!req.headers['authorization'] && apiKeyHeader) {
req.headers['authorization'] = `Bearer ${req.headers['x-api-key']}` req.headers['authorization'] = `Bearer ${apiKeyHeader}`
} }
// 添加必要的Anthropic头 // 添加必要的Anthropic头

View File

@@ -13,13 +13,10 @@ const { updateRateLimitCounters } = require('../utils/rateLimitHelper')
// 生成会话哈希 // 生成会话哈希
function generateSessionHash(req) { function generateSessionHash(req) {
const sessionData = [ const apiKeyPrefix =
req.headers['user-agent'], req.headers['x-api-key']?.substring(0, 10) || req.headers['x-goog-api-key']?.substring(0, 10)
req.ip,
req.headers['x-api-key']?.substring(0, 10) const sessionData = [req.headers['user-agent'], req.ip, apiKeyPrefix].filter(Boolean).join(':')
]
.filter(Boolean)
.join(':')
return crypto.createHash('sha256').update(sessionData).digest('hex') return crypto.createHash('sha256').update(sessionData).digest('hex')
} }

View File

@@ -9,11 +9,10 @@ const crypto = require('crypto')
// 生成会话哈希 // 生成会话哈希
function generateSessionHash(req) { function generateSessionHash(req) {
const sessionData = [ const authSource =
req.headers['user-agent'], req.headers['authorization'] || req.headers['x-api-key'] || req.headers['x-goog-api-key']
req.ip,
req.headers['authorization']?.substring(0, 20) const sessionData = [req.headers['user-agent'], req.ip, authSource?.substring(0, 20)]
]
.filter(Boolean) .filter(Boolean)
.join(':') .join(':')