From 24858f7e51306f332c583482ac72e06631d9aef1 Mon Sep 17 00:00:00 2001 From: shaw Date: Sat, 26 Jul 2025 13:47:34 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E5=8A=A0=E8=A7=A3=E5=AF=86=E7=9B=B8=E5=85=B3=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根据用户要求删除临时调试脚本,准备重新分析加密流程 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- scripts/debug-gemini-decrypt.js | 146 ------------------------ scripts/fix-gemini-default-key.js | 182 ------------------------------ scripts/fix-gemini-encryption.js | 169 --------------------------- scripts/update-gemini-token.js | 77 ------------- 4 files changed, 574 deletions(-) delete mode 100644 scripts/debug-gemini-decrypt.js delete mode 100644 scripts/fix-gemini-default-key.js delete mode 100644 scripts/fix-gemini-encryption.js delete mode 100644 scripts/update-gemini-token.js diff --git a/scripts/debug-gemini-decrypt.js b/scripts/debug-gemini-decrypt.js deleted file mode 100644 index 7b481189..00000000 --- a/scripts/debug-gemini-decrypt.js +++ /dev/null @@ -1,146 +0,0 @@ -#!/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 config = require('../config/config'); - -const ALGORITHM = 'aes-256-cbc'; -const IV_LENGTH = 16; -const GEMINI_ACCOUNT_KEY_PREFIX = 'gemini_account:'; -const ENCRYPTION_SALT = 'gemini-encryption-salt-2024'; - -// 生成加密密钥(使用与 geminiAccountService 相同的方法) -function generateEncryptionKey() { - return crypto.scryptSync(config.security.encryptionKey, ENCRYPTION_SALT, 32); -} - -// 旧版解密函数(使用冒号分隔) -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(` config.security.encryptionKey: ${config.security.encryptionKey}`); - console.log(` 实际使用的加密密钥长度: ${config.security.encryptionKey.length}`); - console.log(` ENCRYPTION_SALT: ${ENCRYPTION_SALT}`); - 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 diff --git a/scripts/fix-gemini-default-key.js b/scripts/fix-gemini-default-key.js deleted file mode 100644 index 82f93ab1..00000000 --- a/scripts/fix-gemini-default-key.js +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env node - -/** - * 修复使用默认密钥加密的 Gemini 账户数据 - */ - -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 config = require('../config/config'); - -const ALGORITHM = 'aes-256-cbc'; -const IV_LENGTH = 16; -const GEMINI_ACCOUNT_KEY_PREFIX = 'gemini_account:'; -const ENCRYPTION_SALT = 'gemini-encryption-salt-2024'; - -// 默认密钥(可能在创建时使用) -const DEFAULT_KEY = 'default-encryption-key-change-in-production'; - -// 生成加密密钥(使用默认密钥) -function generateDefaultKey() { - return crypto.scryptSync(DEFAULT_KEY, ENCRYPTION_SALT, 32); -} - -// 生成加密密钥(使用当前配置) -function generateCurrentKey() { - return crypto.scryptSync(config.security.encryptionKey, ENCRYPTION_SALT, 32); -} - -// 尝试使用指定密钥解密 -function decryptWithKey(text, key) { - if (!text) return ''; - try { - // 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 null; - } -} - -// 使用当前密钥加密 -function encryptWithCurrentKey(text) { - if (!text) return ''; - const key = generateCurrentKey(); - const iv = crypto.randomBytes(IV_LENGTH); - const cipher = crypto.createCipheriv(ALGORITHM, key, iv); - let encrypted = cipher.update(text); - encrypted = Buffer.concat([encrypted, cipher.final()]); - return iv.toString('hex') + ':' + encrypted.toString('hex'); -} - -async function fixGeminiDefaultKey() { - try { - console.log('🚀 开始修复使用默认密钥加密的 Gemini 账户...\n'); - - // 显示密钥信息 - console.log('📋 密钥信息:'); - console.log(` 默认密钥: ${DEFAULT_KEY}`); - console.log(` 当前密钥: ${config.security.encryptionKey}`); - console.log(` 密钥相同: ${DEFAULT_KEY === config.security.encryptionKey ? '是' : '否'}`); - console.log(); - - // 连接 Redis - console.log('📡 连接 Redis...'); - await redis.connect(); - console.log('✅ Redis 连接成功\n'); - - 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`); - - let fixedCount = 0; - - 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})`); - - if (!accountData.refreshToken) { - console.log(' ⚠️ 无 refreshToken,跳过'); - continue; - } - - // 生成两种密钥 - const defaultKey = generateDefaultKey(); - const currentKey = generateCurrentKey(); - - // 先尝试用当前密钥解密 - console.log(' 🔐 尝试使用当前密钥解密...'); - let decryptedToken = decryptWithKey(accountData.refreshToken, currentKey); - - if (decryptedToken && decryptedToken.startsWith('1//')) { - console.log(' ✅ 当前密钥解密成功,无需修复'); - continue; - } - - // 尝试用默认密钥解密 - console.log(' 🔐 尝试使用默认密钥解密...'); - decryptedToken = decryptWithKey(accountData.refreshToken, defaultKey); - - if (!decryptedToken || !decryptedToken.startsWith('1//')) { - console.log(' ❌ 两种密钥都无法解密!'); - console.log(' 💡 可能需要手动更新 refresh token'); - continue; - } - - console.log(' ✅ 默认密钥解密成功!'); - console.log(` 📝 Token 前缀: ${decryptedToken.substring(0, 10)}...`); - - if (process.argv.includes('--fix')) { - // 使用当前密钥重新加密 - console.log(' 🔄 使用当前密钥重新加密...'); - - const updates = {}; - - // 重新加密 refreshToken - updates.refreshToken = encryptWithCurrentKey(decryptedToken); - - // 同样处理 accessToken 和 geminiOauth - if (accountData.accessToken) { - const decryptedAccess = decryptWithKey(accountData.accessToken, defaultKey); - if (decryptedAccess) { - updates.accessToken = encryptWithCurrentKey(decryptedAccess); - } - } - - if (accountData.geminiOauth) { - const decryptedOauth = decryptWithKey(accountData.geminiOauth, defaultKey); - if (decryptedOauth) { - updates.geminiOauth = encryptWithCurrentKey(decryptedOauth); - } - } - - // 更新 Redis - await client.hmset(key, updates); - console.log(' ✅ 已重新加密并保存'); - fixedCount++; - } else { - console.log(' ⚠️ 使用 --fix 参数来修复此账户'); - } - } - - console.log('\n' + '='.repeat(60)); - - if (process.argv.includes('--fix')) { - console.log(`\n✅ 修复完成!共修复 ${fixedCount} 个账户`); - } else { - console.log('\n💡 提示:使用 --fix 参数运行脚本以修复问题'); - console.log(' node scripts/fix-gemini-default-key.js --fix'); - } - - } catch (error) { - console.error('❌ 修复失败:', error); - } finally { - await redis.disconnect(); - process.exit(0); - } -} - -// 运行修复 -fixGeminiDefaultKey(); \ No newline at end of file diff --git a/scripts/fix-gemini-encryption.js b/scripts/fix-gemini-encryption.js deleted file mode 100644 index 9d136f73..00000000 --- a/scripts/fix-gemini-encryption.js +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env node - -/** - * 修复 Gemini 账户的加密数据 - * - * 问题:线上数据可能是用旧版本的加密方式存储的,需要重新加密 - */ - -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 config = require('../config/config'); - -const ALGORITHM = 'aes-256-cbc'; -const IV_LENGTH = 16; -const GEMINI_ACCOUNT_KEY_PREFIX = 'gemini_account:'; -const ENCRYPTION_SALT = 'gemini-encryption-salt-2024'; - -// 生成加密密钥(使用与 geminiAccountService 相同的方法) -function generateEncryptionKey() { - return crypto.scryptSync(config.security.encryptionKey, ENCRYPTION_SALT, 32); -} - -// 新的加密函数 -function encrypt(text) { - if (!text) return ''; - const key = generateEncryptionKey(); - const iv = crypto.randomBytes(IV_LENGTH); - const cipher = crypto.createCipheriv(ALGORITHM, key, iv); - let encrypted = cipher.update(text); - encrypted = Buffer.concat([encrypted, cipher.final()]); - return iv.toString('hex') + ':' + encrypted.toString('hex'); -} - -// 新的解密函数 -function decrypt(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) { - console.error('Decryption error:', error); - return null; - } -} - -// 尝试多种解密方法 -function tryDecrypt(encryptedText) { - // 1. 尝试直接返回(可能未加密) - if (encryptedText && encryptedText.startsWith('1//')) { - console.log(' 📝 数据看起来未加密(Google refresh token 格式)'); - return encryptedText; - } - - // 2. 尝试标准解密 - const result = decrypt(encryptedText); - if (result && result.startsWith('1//')) { - console.log(' ✅ 使用标准解密成功'); - return result; - } - - // 3. 可能是用不同的密钥加密的 - console.log(' ❌ 无法解密,可能需要原始 refresh token'); - return null; -} - -async function fixGeminiEncryption() { - try { - console.log('🚀 开始修复 Gemini 账户加密...\n'); - - // 显示加密配置 - console.log('📋 当前加密配置:'); - console.log(` config.security.encryptionKey: ${config.security.encryptionKey}`); - console.log(` 密钥长度: ${config.security.encryptionKey.length}`); - console.log(` ENCRYPTION_SALT: ${ENCRYPTION_SALT}`); - console.log(); - - // 连接 Redis - console.log('📡 连接 Redis...'); - await redis.connect(); - console.log('✅ Redis 连接成功\n'); - - 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})`); - - if (!accountData.refreshToken) { - console.log(' ⚠️ 无 refreshToken,跳过'); - continue; - } - - // 尝试解密 - console.log(' 🔐 尝试解密 refreshToken...'); - const decryptedToken = tryDecrypt(accountData.refreshToken); - - if (!decryptedToken) { - console.log(' ❌ 解密失败!'); - console.log(' 💡 建议:请提供原始的 refresh token 以修复此账户'); - console.log(` 📝 使用命令: npm run cli gemini-accounts update ${accountId} --refresh-token "YOUR_REFRESH_TOKEN"`); - continue; - } - - // 检查是否需要重新加密 - const testEncrypted = encrypt(decryptedToken); - if (testEncrypted === accountData.refreshToken) { - console.log(' ✅ 加密正常,无需修复'); - continue; - } - - console.log(' 🔄 需要重新加密...'); - console.log(` 解密后的 token 前缀: ${decryptedToken.substring(0, 10)}...`); - - // 询问是否要修复 - console.log('\n ⚠️ 警告:这将重新加密 refreshToken'); - console.log(' 建议先备份当前数据!'); - console.log(' 如果要继续修复,请使用 --fix 参数运行脚本'); - - if (process.argv.includes('--fix')) { - // 重新加密并更新 - const newEncrypted = encrypt(decryptedToken); - await client.hset(key, 'refreshToken', newEncrypted); - console.log(' ✅ 已重新加密并保存'); - } - } - - console.log('\n✅ 检查完成!'); - - if (!process.argv.includes('--fix')) { - console.log('\n💡 提示:使用 --fix 参数运行脚本以修复加密问题'); - console.log(' node scripts/fix-gemini-encryption.js --fix'); - } - - } catch (error) { - console.error('❌ 修复失败:', error); - } finally { - await redis.disconnect(); - process.exit(0); - } -} - -// 运行修复 -fixGeminiEncryption(); \ No newline at end of file diff --git a/scripts/update-gemini-token.js b/scripts/update-gemini-token.js deleted file mode 100644 index 208a3b44..00000000 --- a/scripts/update-gemini-token.js +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env node - -/** - * 手动更新 Gemini 账户的 refresh token - */ - -const path = require('path'); -const dotenv = require('dotenv'); - -// 加载环境变量 -dotenv.config({ path: path.join(__dirname, '..', '.env') }); - -const redis = require('../src/models/redis'); -const geminiAccountService = require('../src/services/geminiAccountService'); -const logger = require('../src/utils/logger'); - -async function updateGeminiRefreshToken() { - const accountId = process.argv[2]; - const refreshToken = process.argv[3]; - - if (!accountId || !refreshToken) { - console.log('❌ 用法: node scripts/update-gemini-token.js '); - console.log('\n示例:'); - console.log('node scripts/update-gemini-token.js 16befd10-9691-43d8-8a8a-39b6fd83dbc0 "1//0gEXAMPLE..."'); - process.exit(1); - } - - try { - console.log('🚀 开始更新 Gemini refresh token...\n'); - - // 连接 Redis - console.log('📡 连接 Redis...'); - await redis.connect(); - console.log('✅ Redis 连接成功\n'); - - // 获取账户 - const account = await geminiAccountService.getAccount(accountId); - if (!account) { - console.log(`❌ 未找到账户: ${accountId}`); - process.exit(1); - } - - console.log(`📋 找到账户: ${account.name} (${accountId})`); - console.log(` 当前状态: ${account.status}`); - - // 更新 refresh token - console.log('\n🔄 更新 refresh token...'); - await geminiAccountService.updateAccount(accountId, { - refreshToken: refreshToken, - status: 'active', - errorMessage: '' - }); - - console.log('✅ Refresh token 已更新!'); - - // 立即尝试刷新 token - console.log('\n🔄 尝试刷新 access token...'); - try { - const newTokens = await geminiAccountService.refreshAccountToken(accountId); - console.log('✅ Token 刷新成功!'); - console.log(` Access Token 前缀: ${newTokens.access_token.substring(0, 20)}...`); - console.log(` 过期时间: ${new Date(newTokens.expiry_date).toLocaleString()}`); - } catch (error) { - console.log(`❌ Token 刷新失败: ${error.message}`); - console.log(' 请检查 refresh token 是否有效'); - } - - } catch (error) { - console.error('❌ 更新失败:', error); - } finally { - await redis.disconnect(); - process.exit(0); - } -} - -// 运行更新 -updateGeminiRefreshToken(); \ No newline at end of file