mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 适配新版本gemini
This commit is contained in:
@@ -65,6 +65,44 @@ const TOKEN_COUNT_PATHS = new Set([
|
||||
'/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) {
|
||||
if (!value) {
|
||||
return '/'
|
||||
@@ -95,18 +133,18 @@ const authenticateApiKey = async (req, res, next) => {
|
||||
|
||||
try {
|
||||
// 安全提取API Key,支持多种格式(包括Gemini CLI支持)
|
||||
const apiKey =
|
||||
req.headers['x-api-key'] ||
|
||||
req.headers['x-goog-api-key'] ||
|
||||
req.headers['authorization']?.replace(/^Bearer\s+/i, '') ||
|
||||
req.headers['api-key'] ||
|
||||
req.query.key
|
||||
const apiKey = extractApiKey(req)
|
||||
|
||||
if (apiKey) {
|
||||
req.headers['x-api-key'] = apiKey
|
||||
}
|
||||
|
||||
if (!apiKey) {
|
||||
logger.security(`🔒 Missing API key attempt from ${req.ip || 'unknown'}`)
|
||||
return res.status(401).json({
|
||||
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',
|
||||
'Authorization',
|
||||
'x-api-key',
|
||||
'x-goog-api-key',
|
||||
'api-key',
|
||||
'x-admin-token',
|
||||
'anthropic-version',
|
||||
|
||||
@@ -7,12 +7,38 @@ const logger = require('../utils/logger')
|
||||
const browserFallbackMiddleware = (req, res, next) => {
|
||||
const userAgent = req.headers['user-agent'] || ''
|
||||
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插件或浏览器请求
|
||||
const isChromeExtension = origin.startsWith('chrome-extension://')
|
||||
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) {
|
||||
// 为Chrome插件请求添加特殊标记
|
||||
@@ -23,8 +49,8 @@ const browserFallbackMiddleware = (req, res, next) => {
|
||||
req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)'
|
||||
|
||||
// 确保设置正确的认证头
|
||||
if (!req.headers['authorization'] && req.headers['x-api-key']) {
|
||||
req.headers['authorization'] = `Bearer ${req.headers['x-api-key']}`
|
||||
if (!req.headers['authorization'] && apiKeyHeader) {
|
||||
req.headers['authorization'] = `Bearer ${apiKeyHeader}`
|
||||
}
|
||||
|
||||
// 添加必要的Anthropic头
|
||||
|
||||
@@ -13,13 +13,10 @@ const { updateRateLimitCounters } = require('../utils/rateLimitHelper')
|
||||
|
||||
// 生成会话哈希
|
||||
function generateSessionHash(req) {
|
||||
const sessionData = [
|
||||
req.headers['user-agent'],
|
||||
req.ip,
|
||||
req.headers['x-api-key']?.substring(0, 10)
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(':')
|
||||
const apiKeyPrefix =
|
||||
req.headers['x-api-key']?.substring(0, 10) || req.headers['x-goog-api-key']?.substring(0, 10)
|
||||
|
||||
const sessionData = [req.headers['user-agent'], req.ip, apiKeyPrefix].filter(Boolean).join(':')
|
||||
|
||||
return crypto.createHash('sha256').update(sessionData).digest('hex')
|
||||
}
|
||||
|
||||
@@ -9,11 +9,10 @@ const crypto = require('crypto')
|
||||
|
||||
// 生成会话哈希
|
||||
function generateSessionHash(req) {
|
||||
const sessionData = [
|
||||
req.headers['user-agent'],
|
||||
req.ip,
|
||||
req.headers['authorization']?.substring(0, 20)
|
||||
]
|
||||
const authSource =
|
||||
req.headers['authorization'] || req.headers['x-api-key'] || req.headers['x-goog-api-key']
|
||||
|
||||
const sessionData = [req.headers['user-agent'], req.ip, authSource?.substring(0, 20)]
|
||||
.filter(Boolean)
|
||||
.join(':')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user