From cd5b39514a2f1be8f51907cfb56e7d18b324fb48 Mon Sep 17 00:00:00 2001 From: Icyoung <337884991@qq.com> Date: Sat, 8 Nov 2025 11:28:51 +0800 Subject: [PATCH] Dev api bugfix (#740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: remove admin mode * feat: bugfix * feat(crypto): 添加RSA-OAEP + AES-GCM混合加密服务 - 实现CryptoService加密服务,支持RSA-OAEP-2048 + AES-256-GCM混合加密 - 集成数据库层加密,自动加密存储敏感字段(API密钥、私钥等) - 支持环境变量DATA_ENCRYPTION_KEY配置数据加密密钥 - 适配SQLite数据库加密存储(从PostgreSQL移植) - 保持Hyperliquid代理钱包处理兼容性 - 更新.gitignore以正确处理crypto模块代码 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(scripts): 添加加密环境一键设置脚本 - setup_encryption.sh: 一键生成RSA密钥对+数据加密密钥+JWT密钥 - generate_rsa_keys.sh: 专业的RSA-2048密钥对生成工具 - generate_data_key.sh: 生成AES-256数据加密密钥和JWT认证密钥 - ENCRYPTION_README.md: 详细的加密系统说明文档 - 支持自动检测现有密钥并只生成缺失的密钥 - 完善的权限管理和安全验证 - 兼容macOS和Linux的跨平台支持 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(api): 添加加密API端点和Gin框架集成 - 新增CryptoHandler处理加密相关API请求 - 提供/api/crypto/public-key端点获取RSA公钥 - 提供/api/crypto/decrypt端点解密敏感数据 - 适配Gin框架的HTTP处理器格式 - 集成CryptoService到API服务器 - 支持前端加密数据传输和解密 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(web): 添加前端加密服务和两阶段密钥输入组件 - CryptoService: Web Crypto API集成,支持RSA-OAEP加密 - TwoStageKeyModal: 安全的两阶段私钥输入组件,支持剪贴板混淆 - 完善国际化翻译支持加密相关UI文本 - 修复TypeScript类型错误和编译问题 - 支持前端敏感数据加密传输到后端 - 增强用户隐私保护和数据安全 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(auth): 增强JWT认证安全性 - 优先使用环境变量JWT_SECRET而不是数据库配置 - 支持通过.env文件安全配置JWT认证密钥 - 保留数据库配置作为回退机制 - 改进JWT密钥来源日志显示 - 增强系统启动时的安全配置检查 - 支持运行时动态JWT密钥切换 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(docker): 集成加密环境变量到Docker部署 - 添加DATA_ENCRYPTION_KEY环境变量传递到容器 - 添加JWT_SECRET环境变量支持 - 挂载secrets目录使容器可访问RSA密钥文件 - 确保容器内加密服务正常工作 - 解决容器启动失败和加密初始化问题 - 完善Docker Compose加密环境配置 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat(start): 集成自动加密环境检测和设置 - 增强check_encryption()函数检测JWT_SECRET和DATA_ENCRYPTION_KEY - 自动运行setup_encryption.sh当检测到缺失密钥时 - 改进加密状态显示,包含RSA+AES+JWT全套加密信息 - 优化用户体验,提供清晰的加密配置反馈 - 支持一键设置完整加密环境 - 确保容器启动前加密环境就绪 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat: format fix * fix(security): 修复前端模型和交易所配置敏感数据明文传输 - 在handleSaveModelConfig中对API密钥进行RSA-OAEP加密 - 在handleSaveExchangeConfig中对API密钥、Secret密钥和Aster私钥进行加密 - 只有非空敏感数据才进行加密处理 - 添加加密失败错误处理和用户友好提示 - 增加encryptionFailed翻译键的中英文支持 - 使用用户ID和会话ID作为加密上下文增强安全性 这修复了之前敏感数据在网络传输中以明文形式发送的安全漏洞。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * fix(crypto): 修复后端加密服务集成和缺失的加密端点 - 添加Server结构体缺少的cryptoService字段 - 实现handleUpdateModelConfigsEncrypted处理器用于模型配置加密传输 - 修复handleUpdateExchangeConfigsEncrypted中的函数调用 - 在前端API中添加updateModelConfigsEncrypted方法 - 统一RSA密钥路径从secrets/rsa_key改为keys/rsa_private.key - 确保前端可以使用加密端点安全传输敏感数据 - 兼容原有加密通信模式和二段输入私钥功能 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * fix(crypto): 完善加密端点配置,简化API结构 - 移除多余的/models/encrypted端点,模型配置暂不加密 - 确认/exchanges端点已强制要求加密传输 - 统一前端使用标准端点,自动使用加密传输 - 修复前端API调用,移除不存在的updateModelConfigsEncrypted引用 - 确保后端和前端编译成功,加密功能正常工作 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * fix(crypto): 为模型配置端点添加加密传输支持 - 前端updateModelConfigs方法现在使用加密传输 - 后端/api/models端点已强制要求加密载荷 - 模型配置界面保持普通输入,在提交时自动加密 - 确保API密钥等敏感数据通过RSA+AES混合加密传输 - 前端后端编译测试通过,加密功能正常工作 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: icy Co-authored-by: Claude --- scripts/setup_encryption.sh | 127 +++++++++++++++++++-------- start.sh | 56 +++++++----- web/src/components/AITradersPage.tsx | 4 +- web/src/lib/api.ts | 16 +--- 4 files changed, 129 insertions(+), 74 deletions(-) diff --git a/scripts/setup_encryption.sh b/scripts/setup_encryption.sh index 35b22c87..506c7b95 100755 --- a/scripts/setup_encryption.sh +++ b/scripts/setup_encryption.sh @@ -58,16 +58,16 @@ echo -e " • 私钥文件: ${YELLOW}$PRIVATE_KEY_FILE${NC}" echo -e " • 公钥文件: ${YELLOW}$PUBLIC_KEY_FILE${NC}" echo -e " • AES密钥: ${YELLOW}256 bits (自动生成)${NC}" -# 显示必要性说明 +# 询问用户确认 echo -echo -e "${YELLOW}⚠️ 加密环境是系统运行的必需条件(不可跳过)${NC}" -echo -e "${BLUE}ℹ️ 将自动检查并生成以下密钥:${NC}" -echo -e " • RSA-2048 密钥对 (用于传输加密)" -echo -e " • AES-256 数据加密密钥 (用于数据库加密)" -echo -e " • JWT 认证密钥 (用于用户认证)" -echo -e "${BLUE}ℹ️ 如果密钥已存在,将保持现有密钥;如果缺失,将自动生成${NC}" +read -p "是否继续设置加密环境? [Y/n]: " -n 1 -r echo +if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "${BLUE}ℹ️ 操作已取消${NC}" + exit 0 +fi +echo echo -e "${CYAN}🚀 开始设置加密环境...${NC}" # ============= 步骤1: 创建目录 ============= @@ -94,20 +94,20 @@ echo echo -e "${YELLOW}🔐 步骤 2/4: 生成 RSA-$RSA_KEY_SIZE 密钥对...${NC}" # 检查现有RSA密钥 -if [ -f "$PRIVATE_KEY_FILE" ] && [ -f "$PUBLIC_KEY_FILE" ]; then - echo -e "${BLUE}ℹ️ 检测到现有的RSA密钥文件,保持现有密钥${NC}" - # 验证现有密钥 - echo -e " ${CYAN}验证现有密钥对...${NC}" - if openssl rsa -in "$PRIVATE_KEY_FILE" -check -noout 2>/dev/null; then - echo -e "${GREEN} ✓ 现有密钥验证通过${NC}" - else - echo -e "${RED} ❌ 现有密钥验证失败,将重新生成${NC}" +if [ -f "$PRIVATE_KEY_FILE" ] || [ -f "$PUBLIC_KEY_FILE" ]; then + echo -e "${YELLOW}⚠️ 检测到现有的RSA密钥文件${NC}" + read -p "是否重新生成RSA密钥? [y/N]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then rm -f "$PRIVATE_KEY_FILE" "$PUBLIC_KEY_FILE" + echo -e "${YELLOW}🗑️ 删除旧密钥${NC}" + else + echo -e "${BLUE}ℹ️ 保持现有RSA密钥${NC}" + RSA_SKIPPED=true fi fi -# 如果密钥不存在或验证失败,生成新密钥 -if [ ! -f "$PRIVATE_KEY_FILE" ] || [ ! -f "$PUBLIC_KEY_FILE" ]; then +if [ "$RSA_SKIPPED" != "true" ]; then # 生成私钥 echo -e " ${CYAN}生成RSA私钥...${NC}" openssl genrsa -out "$PRIVATE_KEY_FILE" $RSA_KEY_SIZE 2>/dev/null @@ -143,33 +143,88 @@ if [ -f ".env" ]; then fi fi -# 确保 .env 文件存在 -if [ ! -f ".env" ]; then - touch .env +if [ "$DATA_KEY_EXISTS" = "true" ] || [ "$JWT_KEY_EXISTS" = "true" ]; then + echo -e "${YELLOW}⚠️ 检测到现有的密钥配置${NC}" + if [ "$DATA_KEY_EXISTS" = "true" ]; then + echo -e " • 数据加密密钥已存在" + fi + if [ "$JWT_KEY_EXISTS" = "true" ]; then + echo -e " • JWT认证密钥已存在" + fi + read -p "是否重新生成所有密钥? [y/N]: " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${BLUE}ℹ️ 保持现有密钥${NC}" + KEY_SKIPPED=true + # 读取现有密钥 + if [ "$DATA_KEY_EXISTS" = "true" ]; then + DATA_KEY=$(grep "^DATA_ENCRYPTION_KEY=" .env | cut -d'=' -f2) + fi + if [ "$JWT_KEY_EXISTS" = "true" ]; then + JWT_KEY=$(grep "^JWT_SECRET=" .env | cut -d'=' -f2) + fi + fi fi -# 生成缺失的密钥(必需,不允许跳过) -if [ "$DATA_KEY_EXISTS" != "true" ]; then +if [ "$KEY_SKIPPED" != "true" ]; then + # 生成新的密钥 echo -e " ${CYAN}生成AES-256数据加密密钥...${NC}" - DATA_KEY=$(openssl rand -base64 32 | tr -d '\n') - echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + DATA_KEY=$(openssl rand -base64 32) echo -e "${GREEN} ✓ 数据加密密钥生成完成${NC}" -else - echo -e "${BLUE} ℹ️ 数据加密密钥已存在,保持现有密钥${NC}" -fi - -if [ "$JWT_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成JWT认证密钥...${NC}" - JWT_KEY=$(openssl rand -base64 64 | tr -d '\n') - echo "JWT_SECRET=$JWT_KEY" >> .env + JWT_KEY=$(openssl rand -base64 64) echo -e "${GREEN} ✓ JWT认证密钥生成完成${NC}" -else - echo -e "${BLUE} ℹ️ JWT认证密钥已存在,保持现有密钥${NC}" + + # 保存到.env文件 + if [ -f ".env" ]; then + # 更新现有文件 + if grep -q "^DATA_ENCRYPTION_KEY=" .env; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/^DATA_ENCRYPTION_KEY=.*/DATA_ENCRYPTION_KEY=$DATA_KEY/" .env + else + sed -i "s/^DATA_ENCRYPTION_KEY=.*/DATA_ENCRYPTION_KEY=$DATA_KEY/" .env + fi + else + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + fi + + if grep -q "^JWT_SECRET=" .env; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/^JWT_SECRET=.*/JWT_SECRET=$JWT_KEY/" .env + else + sed -i "s/^JWT_SECRET=.*/JWT_SECRET=$JWT_KEY/" .env + fi + else + echo "JWT_SECRET=$JWT_KEY" >> .env + fi + else + # 创建新文件 + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" > .env + echo "JWT_SECRET=$JWT_KEY" >> .env + fi + chmod 600 .env + echo -e "${GREEN} ✓ 密钥已保存到 .env 文件${NC}" +elif [ "$DATA_KEY_EXISTS" != "true" ] || [ "$JWT_KEY_EXISTS" != "true" ]; then + # 生成缺失的密钥 + if [ "$DATA_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成缺失的AES-256数据加密密钥...${NC}" + DATA_KEY=$(openssl rand -base64 32) + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + echo -e "${GREEN} ✓ 数据加密密钥生成完成${NC}" + fi + + if [ "$JWT_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成缺失的JWT认证密钥...${NC}" + JWT_KEY=$(openssl rand -base64 64) + echo "JWT_SECRET=$JWT_KEY" >> .env + echo -e "${GREEN} ✓ JWT认证密钥生成完成${NC}" + fi + + chmod 600 .env + echo -e "${GREEN} ✓ 密钥已保存到 .env 文件${NC}" fi -chmod 600 .env -echo -e "${GREEN} ✓ 密钥配置已保存到 .env 文件${NC}" - # ============= 步骤4: 验证和总结 ============= echo echo -e "${YELLOW}✅ 步骤 4/4: 环境验证和总结...${NC}" diff --git a/start.sh b/start.sh index ef59b772..2f7eb452 100755 --- a/start.sh +++ b/start.sh @@ -104,37 +104,47 @@ check_encryption() { # 如果需要设置加密环境 if [ "$need_setup" = "true" ]; then - print_info "🔐 需要设置加密环境(必需)" + print_info "🔐 需要设置加密环境" print_info "加密环境用于保护敏感数据(API密钥、私钥等)" - print_info "系统将自动配置加密环境..." echo "" - - # 检查加密设置脚本是否存在 - if [ -f "scripts/setup_encryption.sh" ]; then - print_info "正在自动设置加密环境..." - print_info "加密系统将保护: API密钥、私钥、Hyperliquid代理钱包" - echo "" - - # 自动运行加密设置脚本 - # n: 保持现有RSA密钥(如果存在)| n: 保持现有数据密钥(如果存在) - echo -e "n\nn" | bash scripts/setup_encryption.sh - if [ $? -eq 0 ]; then - echo "" - print_success "🔐 加密环境设置完成!" - print_info " • RSA-2048密钥对已生成" - print_info " • AES-256数据加密密钥已配置" - print_info " • JWT认证密钥已配置" - print_info " • 所有敏感数据现在都受加密保护" + + # 询问用户是否自动设置 + read -p "是否自动设置加密环境?[Y/n]: " auto_setup + auto_setup=${auto_setup:-Y} + + if [[ "$auto_setup" =~ ^[Yy]$ ]]; then + print_info "正在设置加密环境..." + + # 检查加密设置脚本是否存在 + if [ -f "scripts/setup_encryption.sh" ]; then + print_info "正在自动设置加密环境..." + print_info "加密系统将保护: API密钥、私钥、Hyperliquid代理钱包" echo "" + + # 自动运行加密设置脚本 + # Y: 继续设置加密环境 | n: 保持现有RSA密钥 | n: 保持现有密钥配置 + echo -e "Y\nn\nn" | bash scripts/setup_encryption.sh + if [ $? -eq 0 ]; then + echo "" + print_success "🔐 加密环境设置完成!" + print_info " • RSA-2048密钥对已生成" + print_info " • AES-256数据加密密钥已配置" + print_info " • JWT认证密钥已配置" + print_info " • 所有敏感数据现在都受加密保护" + echo "" + else + print_error "加密环境设置失败" + exit 1 + fi else - print_error "加密环境设置失败" + print_error "加密设置脚本不存在: scripts/setup_encryption.sh" print_info "请手动运行: ./scripts/setup_encryption.sh" exit 1 fi else - print_error "加密设置脚本不存在: scripts/setup_encryption.sh" - print_info "请手动运行: ./scripts/setup_encryption.sh" - exit 1 + print_warning "跳过加密环境设置" + print_info "手动设置命令: ./scripts/setup_encryption.sh" + print_info "系统将使用未加密模式运行(不推荐)" fi else print_success "🔐 加密环境已配置" diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index 1e55bc9a..322d66b3 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -415,7 +415,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ]) ), }), - updateApi: api.updateModelConfigsEncrypted, + updateApi: api.updateModelConfigs, refreshApi: api.getModelConfigs, setItems: (items) => { // 使用函数式更新确保状态正确更新 @@ -488,7 +488,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ), } - await api.updateModelConfigsEncrypted(request) + await api.updateModelConfigs(request) // 重新获取用户配置以确保数据同步 const refreshedModels = await api.getModelConfigs() diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 0bd79d8f..3d3eda69 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -131,18 +131,6 @@ export const api = { }, async updateModelConfigs(request: UpdateModelConfigRequest): Promise { - const res = await fetch(`${API_BASE}/models`, { - method: 'PUT', - headers: getAuthHeaders(), - body: JSON.stringify(request), - }) - if (!res.ok) throw new Error('更新模型配置失败') - }, - - // 使用加密传输更新模型配置 - async updateModelConfigsEncrypted( - request: UpdateModelConfigRequest - ): Promise { // 获取RSA公钥 const publicKey = await CryptoService.fetchPublicKey() @@ -160,6 +148,7 @@ export const api = { sessionId ) + // 发送加密数据 const res = await fetch(`${API_BASE}/models`, { method: 'PUT', headers: getAuthHeaders(), @@ -168,6 +157,7 @@ export const api = { if (!res.ok) throw new Error('更新模型配置失败') }, + // 交易所配置接口 async getExchangeConfigs(): Promise { const res = await fetch(`${API_BASE}/exchanges`, { @@ -216,7 +206,7 @@ export const api = { sessionId ) - // 发送加密数据到普通端点 + // 发送加密数据 const res = await fetch(`${API_BASE}/exchanges`, { method: 'PUT', headers: getAuthHeaders(),