mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 添加 Gemini refreshToken 解密调试脚本
- 检查环境变量中的 ENCRYPTION_KEY - 显示加密数据的格式信息 - 尝试新旧两种解密方法 - 输出详细的调试信息帮助定位问题 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
147
scripts/debug-gemini-decrypt.js
Normal file
147
scripts/debug-gemini-decrypt.js
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* 调试 Gemini refreshToken 解密问题
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const dotenv = require('dotenv');
|
||||
const crypto = require('crypto');
|
||||
|
||||
// 加载环境变量
|
||||
dotenv.config({ path: path.join(__dirname, '..', '.env') });
|
||||
|
||||
const redis = require('../src/models/redis');
|
||||
const logger = require('../src/utils/logger');
|
||||
|
||||
const ALGORITHM = 'aes-256-cbc';
|
||||
const IV_LENGTH = 16;
|
||||
const GEMINI_ACCOUNT_KEY_PREFIX = 'gemini_account:';
|
||||
|
||||
// 生成加密密钥
|
||||
function generateEncryptionKey() {
|
||||
const configKey = process.env.ENCRYPTION_KEY;
|
||||
if (!configKey || configKey.length !== 32) {
|
||||
throw new Error('ENCRYPTION_KEY must be exactly 32 characters long');
|
||||
}
|
||||
return Buffer.from(configKey);
|
||||
}
|
||||
|
||||
// 旧版解密函数(使用冒号分隔)
|
||||
function decryptOld(text) {
|
||||
if (!text) return '';
|
||||
try {
|
||||
const key = generateEncryptionKey();
|
||||
const textParts = text.split(':');
|
||||
const iv = Buffer.from(textParts.shift(), 'hex');
|
||||
const encryptedText = Buffer.from(textParts.join(':'), 'hex');
|
||||
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
|
||||
let decrypted = decipher.update(encryptedText);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 新版解密函数(固定长度)
|
||||
function decryptNew(text) {
|
||||
if (!text) return '';
|
||||
try {
|
||||
const key = generateEncryptionKey();
|
||||
// IV 是固定长度的 32 个十六进制字符(16 字节)
|
||||
const ivHex = text.substring(0, 32);
|
||||
const encryptedHex = text.substring(33); // 跳过冒号
|
||||
|
||||
const iv = Buffer.from(ivHex, 'hex');
|
||||
const encryptedText = Buffer.from(encryptedHex, 'hex');
|
||||
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
|
||||
let decrypted = decipher.update(encryptedText);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async function debugGeminiDecrypt() {
|
||||
try {
|
||||
console.log('🚀 开始调试 Gemini refreshToken 解密...\n');
|
||||
|
||||
// 显示环境变量
|
||||
console.log('📋 环境变量检查:');
|
||||
console.log(` ENCRYPTION_KEY 长度: ${process.env.ENCRYPTION_KEY ? process.env.ENCRYPTION_KEY.length : 'undefined'}`);
|
||||
console.log(` ENCRYPTION_KEY 前8位: ${process.env.ENCRYPTION_KEY ? process.env.ENCRYPTION_KEY.substring(0, 8) + '...' : 'undefined'}`);
|
||||
console.log();
|
||||
|
||||
// 连接 Redis
|
||||
console.log('📡 连接 Redis...');
|
||||
await redis.connect();
|
||||
console.log('✅ Redis 连接成功\n');
|
||||
|
||||
// 获取 Gemini 账户
|
||||
const client = redis.getClient();
|
||||
const keys = await client.keys(`${GEMINI_ACCOUNT_KEY_PREFIX}*`);
|
||||
|
||||
if (keys.length === 0) {
|
||||
console.log('❌ 没有找到 Gemini 账户');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`🔍 找到 ${keys.length} 个 Gemini 账户\n`);
|
||||
|
||||
for (const key of keys) {
|
||||
const accountData = await client.hgetall(key);
|
||||
const accountId = key.replace(GEMINI_ACCOUNT_KEY_PREFIX, '');
|
||||
|
||||
console.log(`\n📋 账户: ${accountData.name} (${accountId})`);
|
||||
console.log(` 平台: ${accountData.platform}`);
|
||||
|
||||
if (accountData.refreshToken) {
|
||||
console.log(`\n 🔐 RefreshToken 分析:`);
|
||||
console.log(` 原始长度: ${accountData.refreshToken.length}`);
|
||||
console.log(` 包含冒号: ${accountData.refreshToken.includes(':') ? '是' : '否'}`);
|
||||
console.log(` 前50字符: ${accountData.refreshToken.substring(0, 50)}...`);
|
||||
|
||||
// 尝试旧版解密
|
||||
console.log(`\n 📝 尝试旧版解密(冒号分隔):`);
|
||||
const oldResult = decryptOld(accountData.refreshToken);
|
||||
if (oldResult.error) {
|
||||
console.log(` ❌ 失败: ${oldResult.error}`);
|
||||
} else {
|
||||
console.log(` ✅ 成功!Token前20字符: ${oldResult.substring(0, 20)}...`);
|
||||
}
|
||||
|
||||
// 尝试新版解密
|
||||
console.log(`\n 📝 尝试新版解密(固定长度):`);
|
||||
const newResult = decryptNew(accountData.refreshToken);
|
||||
if (newResult.error) {
|
||||
console.log(` ❌ 失败: ${newResult.error}`);
|
||||
} else {
|
||||
console.log(` ✅ 成功!Token前20字符: ${newResult.substring(0, 20)}...`);
|
||||
}
|
||||
|
||||
// 分析加密格式
|
||||
if (accountData.refreshToken.includes(':')) {
|
||||
const parts = accountData.refreshToken.split(':');
|
||||
console.log(`\n 📊 加密格式分析(按冒号分隔):`);
|
||||
console.log(` 部分数量: ${parts.length}`);
|
||||
console.log(` 第一部分长度: ${parts[0].length} (应为32,即16字节的hex)`);
|
||||
}
|
||||
} else {
|
||||
console.log(` ⚠️ 无 refreshToken`);
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 调试失败:', error);
|
||||
} finally {
|
||||
await redis.disconnect();
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 运行调试
|
||||
debugGeminiDecrypt();
|
||||
Reference in New Issue
Block a user