From a939fcebac340439351797d433cd01e3ece7a406 Mon Sep 17 00:00:00 2001 From: shaw Date: Sat, 26 Jul 2025 12:16:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Gemini=20refreshTo?= =?UTF-8?q?ken=20=E8=A7=A3=E5=AF=86=E8=B0=83=E8=AF=95=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 检查环境变量中的 ENCRYPTION_KEY - 显示加密数据的格式信息 - 尝试新旧两种解密方法 - 输出详细的调试信息帮助定位问题 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- scripts/debug-gemini-decrypt.js | 147 ++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 scripts/debug-gemini-decrypt.js diff --git a/scripts/debug-gemini-decrypt.js b/scripts/debug-gemini-decrypt.js new file mode 100644 index 00000000..d3401bba --- /dev/null +++ b/scripts/debug-gemini-decrypt.js @@ -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(); \ No newline at end of file