import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import dotenv from 'dotenv'; dotenv.config(); const dataDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'data'); const localKeyPath = path.join(dataDir, '.config-encryption-key'); function loadKey(): Buffer { const configured = process.env.COS_CONFIG_ENCRYPTION_KEY?.trim(); if (configured) return createHash('sha256').update(configured, 'utf8').digest(); fs.mkdirSync(dataDir, { recursive: true }); if (!fs.existsSync(localKeyPath)) { fs.writeFileSync(localKeyPath, randomBytes(32).toString('base64'), { encoding: 'utf8', mode: 0o600, flag: 'wx' }); } return Buffer.from(fs.readFileSync(localKeyPath, 'utf8').trim(), 'base64'); } const key = loadKey(); export function encryptSecret(value: string): string { const iv = randomBytes(12); const cipher = createCipheriv('aes-256-gcm', key, iv); const encrypted = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()]); return `v1:${iv.toString('base64')}:${cipher.getAuthTag().toString('base64')}:${encrypted.toString('base64')}`; } export function decryptSecret(value: string): string { const [version, iv, tag, encrypted] = value.split(':'); if (version !== 'v1' || !iv || !tag || !encrypted) throw new Error('无法读取已保存的存储凭证'); const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(iv, 'base64')); decipher.setAuthTag(Buffer.from(tag, 'base64')); return Buffer.concat([decipher.update(Buffer.from(encrypted, 'base64')), decipher.final()]).toString('utf8'); }