import fs from 'fs/promises'; import path from 'path'; import crypto from 'crypto'; import logger from '../utils/logger.js'; const KEYS_FILE = path.join(process.cwd(), 'data', 'api_keys.json'); // 确保数据目录存在 async function ensureDataDir() { const dataDir = path.dirname(KEYS_FILE); try { await fs.access(dataDir); } catch { await fs.mkdir(dataDir, { recursive: true }); } } // 生成随机 API 密钥 function generateApiKey() { return 'sk-' + crypto.randomBytes(32).toString('hex'); } // 加载所有密钥 export async function loadKeys() { await ensureDataDir(); try { const data = await fs.readFile(KEYS_FILE, 'utf-8'); return JSON.parse(data); } catch (error) { if (error.code === 'ENOENT') { return []; } throw error; } } // 保存密钥 async function saveKeys(keys) { await ensureDataDir(); await fs.writeFile(KEYS_FILE, JSON.stringify(keys, null, 2), 'utf-8'); } // 创建新密钥 export async function createKey(name = '未命名', rateLimit = null, customKey = null) { const keys = await loadKeys(); if (customKey) { if (keys.some(k => k.key === customKey)) { throw new Error('密钥已存在'); } } const newKey = { key: customKey || generateApiKey(), name, created: new Date().toISOString(), lastUsed: null, requests: 0, rateLimit: rateLimit || { enabled: false, maxRequests: 100, windowMs: 60000 }, // 默认 100 次/分钟 usage: {} // 用于存储使用记录 { timestamp: count } }; keys.push(newKey); await saveKeys(keys); logger.info(`新密钥已创建: ${name}`); return newKey; } // 删除密钥 export async function deleteKey(keyToDelete) { const keys = await loadKeys(); const filtered = keys.filter(k => k.key !== keyToDelete); if (filtered.length === keys.length) { throw new Error('密钥不存在'); } await saveKeys(filtered); logger.info(`密钥已删除: ${keyToDelete.substring(0, 10)}...`); return true; } // 验证密钥 export async function validateKey(keyToCheck) { const keys = await loadKeys(); const key = keys.find(k => k.key === keyToCheck); if (key) { // 更新使用信息 key.lastUsed = new Date().toISOString(); key.requests = (key.requests || 0) + 1; await saveKeys(keys); return true; } return false; } // 获取密钥统计 export async function getKeyStats() { const keys = await loadKeys(); return { total: keys.length, active: keys.filter(k => k.lastUsed).length, totalRequests: keys.reduce((sum, k) => sum + (k.requests || 0), 0) }; } // 更新密钥频率限制 export async function updateKeyRateLimit(keyToUpdate, rateLimit) { const keys = await loadKeys(); const key = keys.find(k => k.key === keyToUpdate); if (!key) { throw new Error('密钥不存在'); } key.rateLimit = rateLimit; await saveKeys(keys); logger.info(`密钥频率限制已更新: ${keyToUpdate.substring(0, 10)}...`); return key; } // 检查频率限制 export async function checkRateLimit(keyToCheck) { const keys = await loadKeys(); const key = keys.find(k => k.key === keyToCheck); if (!key) { return { allowed: false, error: '密钥不存在' }; } // 如果未启用频率限制,直接允许 if (!key.rateLimit || !key.rateLimit.enabled) { return { allowed: true }; } const now = Date.now(); const windowMs = key.rateLimit.windowMs || 60000; const maxRequests = key.rateLimit.maxRequests || 100; // 清理过期的使用记录 key.usage = key.usage || {}; const cutoffTime = now - windowMs; // 计算当前时间窗口内的请求数 let requestCount = 0; for (const [timestamp, count] of Object.entries(key.usage)) { if (parseInt(timestamp) >= cutoffTime) { requestCount += count; } else { delete key.usage[timestamp]; // 清理过期记录 } } // 检查是否超过限制 if (requestCount >= maxRequests) { const resetTime = Math.min(...Object.keys(key.usage).map(t => parseInt(t))) + windowMs; const waitSeconds = Math.ceil((resetTime - now) / 1000); return { allowed: false, error: '请求频率超限', resetIn: waitSeconds, limit: maxRequests, remaining: 0 }; } // 记录本次请求 const minute = Math.floor(now / 10000) * 10000; // 按10秒分组 key.usage[minute] = (key.usage[minute] || 0) + 1; await saveKeys(keys); return { allowed: true, limit: maxRequests, remaining: maxRequests - requestCount - 1 }; }