Files
LWLT-AIBOT/control-plane/src/crypto.ts
2026-08-25 10:33:29 +08:00

51 lines
2.0 KiB
TypeScript

import { createCipheriv, createDecipheriv, createHash, randomBytes, timingSafeEqual } from 'node:crypto';
import type { AppConfig } from './config.js';
export function randomToken(bytes = 32): string {
return randomBytes(bytes).toString('base64url');
}
export function hashToken(value: string): Buffer {
return createHash('sha256').update(value).digest();
}
export function sameTokenHash(left: Buffer, right: Buffer): boolean {
return left.length === right.length && timingSafeEqual(left, right);
}
export function encryptText(config: AppConfig, value: string): string {
return encryptBytes(config, Buffer.from(value, 'utf8'));
}
export function encryptBytes(config: AppConfig, value: Buffer): string {
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', config.fieldEncryptionKey, iv);
const ciphertext = Buffer.concat([cipher.update(value), cipher.final()]);
const tag = cipher.getAuthTag();
return ['v1', iv.toString('base64url'), tag.toString('base64url'), ciphertext.toString('base64url')].join('.');
}
export function decryptText(config: AppConfig, value: string | null | undefined): string {
return decryptBytes(config, value).toString('utf8');
}
export function decryptBytes(config: AppConfig, value: string | null | undefined): Buffer {
if (!value) return Buffer.alloc(0);
const [version, ivText, tagText, ciphertextText] = value.split('.');
if (version !== 'v1' || !ivText || !tagText || !ciphertextText) throw new Error('Invalid encrypted field format.');
const decipher = createDecipheriv('aes-256-gcm', config.fieldEncryptionKey, Buffer.from(ivText, 'base64url'));
decipher.setAuthTag(Buffer.from(tagText, 'base64url'));
return Buffer.concat([
decipher.update(Buffer.from(ciphertextText, 'base64url')),
decipher.final()
]);
}
export function sha256Text(value: string): string {
return createHash('sha256').update(value).digest('hex');
}
export function sha256Bytes(value: Buffer): string {
return createHash('sha256').update(value).digest('hex');
}