Files
delivery-desk/api/configCrypto.ts

39 lines
1.6 KiB
TypeScript
Raw Permalink Normal View History

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');
}