mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
fix: 代理ip使用重构为统一方法
This commit is contained in:
@@ -5,7 +5,7 @@ const path = require('path')
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
|
||||
// 安全的 JSON 序列化函数,处理循环引用
|
||||
// 安全的 JSON 序列化函数,处理循环引用和特殊字符
|
||||
const safeStringify = (obj, maxDepth = 3, fullDepth = false) => {
|
||||
const seen = new WeakSet()
|
||||
// 如果是fullDepth模式,增加深度限制
|
||||
@@ -16,6 +16,28 @@ const safeStringify = (obj, maxDepth = 3, fullDepth = false) => {
|
||||
return '[Max Depth Reached]'
|
||||
}
|
||||
|
||||
// 处理字符串值,清理可能导致JSON解析错误的特殊字符
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
// 移除或转义可能导致JSON解析错误的字符
|
||||
let cleanValue = value
|
||||
// eslint-disable-next-line no-control-regex
|
||||
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, '') // 移除控制字符
|
||||
.replace(/[\uD800-\uDFFF]/g, '') // 移除孤立的代理对字符
|
||||
// eslint-disable-next-line no-control-regex
|
||||
.replace(/\u0000/g, '') // 移除NUL字节
|
||||
|
||||
// 如果字符串过长,截断并添加省略号
|
||||
if (cleanValue.length > 1000) {
|
||||
cleanValue = `${cleanValue.substring(0, 997)}...`
|
||||
}
|
||||
|
||||
return cleanValue
|
||||
} catch (error) {
|
||||
return '[Invalid String Data]'
|
||||
}
|
||||
}
|
||||
|
||||
if (value !== null && typeof value === 'object') {
|
||||
if (seen.has(value)) {
|
||||
return '[Circular Reference]'
|
||||
@@ -40,7 +62,10 @@ const safeStringify = (obj, maxDepth = 3, fullDepth = false) => {
|
||||
} else {
|
||||
const result = {}
|
||||
for (const [k, v] of Object.entries(value)) {
|
||||
result[k] = replacer(k, v, depth + 1)
|
||||
// 确保键名也是安全的
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const safeKey = typeof k === 'string' ? k.replace(/[\u0000-\u001F\u007F]/g, '') : k
|
||||
result[safeKey] = replacer(safeKey, v, depth + 1)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -50,9 +75,20 @@ const safeStringify = (obj, maxDepth = 3, fullDepth = false) => {
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.stringify(replacer('', obj))
|
||||
const processed = replacer('', obj)
|
||||
return JSON.stringify(processed)
|
||||
} catch (error) {
|
||||
return JSON.stringify({ error: 'Failed to serialize object', message: error.message })
|
||||
// 如果JSON.stringify仍然失败,使用更保守的方法
|
||||
try {
|
||||
return JSON.stringify({
|
||||
error: 'Failed to serialize object',
|
||||
message: error.message,
|
||||
type: typeof obj,
|
||||
keys: obj && typeof obj === 'object' ? Object.keys(obj) : undefined
|
||||
})
|
||||
} catch (finalError) {
|
||||
return '{"error":"Critical serialization failure","message":"Unable to serialize any data"}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,6 +157,14 @@ async function exchangeCodeForTokens(authorizationCode, codeVerifier, state, pro
|
||||
const agent = createProxyAgent(proxyConfig)
|
||||
|
||||
try {
|
||||
if (agent) {
|
||||
logger.info(
|
||||
`🌐 Using proxy for OAuth token exchange: ${ProxyHelper.maskProxyInfo(proxyConfig)}`
|
||||
)
|
||||
} else {
|
||||
logger.debug('🌐 No proxy configured for OAuth token exchange')
|
||||
}
|
||||
|
||||
logger.debug('🔄 Attempting OAuth token exchange', {
|
||||
url: OAUTH_CONFIG.TOKEN_URL,
|
||||
codeLength: cleanedCode.length,
|
||||
@@ -354,6 +362,14 @@ async function exchangeSetupTokenCode(authorizationCode, codeVerifier, state, pr
|
||||
const agent = createProxyAgent(proxyConfig)
|
||||
|
||||
try {
|
||||
if (agent) {
|
||||
logger.info(
|
||||
`🌐 Using proxy for Setup Token exchange: ${ProxyHelper.maskProxyInfo(proxyConfig)}`
|
||||
)
|
||||
} else {
|
||||
logger.debug('🌐 No proxy configured for Setup Token exchange')
|
||||
}
|
||||
|
||||
logger.debug('🔄 Attempting Setup Token exchange', {
|
||||
url: OAUTH_CONFIG.TOKEN_URL,
|
||||
codeLength: cleanedCode.length,
|
||||
|
||||
@@ -163,6 +163,39 @@ class ProxyHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脱敏代理配置信息用于日志记录
|
||||
* @param {object|string} proxyConfig - 代理配置
|
||||
* @returns {string} 脱敏后的代理信息
|
||||
*/
|
||||
static maskProxyInfo(proxyConfig) {
|
||||
if (!proxyConfig) {
|
||||
return 'No proxy'
|
||||
}
|
||||
|
||||
try {
|
||||
const proxy = typeof proxyConfig === 'string' ? JSON.parse(proxyConfig) : proxyConfig
|
||||
|
||||
let proxyDesc = `${proxy.type}://${proxy.host}:${proxy.port}`
|
||||
|
||||
// 如果有认证信息,进行脱敏处理
|
||||
if (proxy.username && proxy.password) {
|
||||
const maskedUsername =
|
||||
proxy.username.length <= 2
|
||||
? proxy.username
|
||||
: proxy.username[0] +
|
||||
'*'.repeat(Math.max(1, proxy.username.length - 2)) +
|
||||
proxy.username.slice(-1)
|
||||
const maskedPassword = '*'.repeat(Math.min(8, proxy.password.length))
|
||||
proxyDesc += ` (auth: ${maskedUsername}:${maskedPassword})`
|
||||
}
|
||||
|
||||
return proxyDesc
|
||||
} catch (error) {
|
||||
return 'Invalid proxy config'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建代理 Agent(兼容旧的函数接口)
|
||||
* @param {object|string|null} proxyConfig - 代理配置
|
||||
|
||||
Reference in New Issue
Block a user