Files
backend/src/integrations/tbank/tbank.crypto.ts
T
ksv741 9cc9fbdcff
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Failing after 2m17s
Conventional commits / commits (pull_request) Successful in 31s
Backend security / security (pull_request) Successful in 8s
Backend verify / verify (pull_request) Failing after 1m56s
refactor: replace ignored numeric literals with constants
2026-09-28 11:24:59 +03:00

52 lines
1.5 KiB
TypeScript

import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
const VERSION_SIZE_BYTES = 1;
const KEY_SIZE_BYTES = 32;
const VERSION = 1;
const NONCE_SIZE = 12;
const TAG_SIZE = 16;
export class TbankCrypto {
constructor(private readonly key: Buffer) {}
static fromBase64(key: string): TbankCrypto {
const decoded = Buffer.from(key, 'base64');
if (decoded.length !== KEY_SIZE_BYTES) {
throw new Error('Invalid token encryption key');
}
return new TbankCrypto(decoded);
}
encrypt(value: string): string {
const nonce = randomBytes(NONCE_SIZE);
const cipher = createCipheriv('aes-256-gcm', this.key, nonce);
const ciphertext = Buffer.concat([
cipher.update(value, 'utf8'),
cipher.final(),
]);
return Buffer.concat([
Buffer.from([VERSION]),
nonce,
ciphertext,
cipher.getAuthTag(),
]).toString('base64');
}
decrypt(payload: string): string {
const bytes = Buffer.from(payload, 'base64');
if (bytes[0] !== VERSION || bytes.length < VERSION_SIZE_BYTES + NONCE_SIZE + TAG_SIZE) {
throw new Error('Invalid encrypted token');
}
const nonce = bytes.subarray(VERSION_SIZE_BYTES, VERSION_SIZE_BYTES + NONCE_SIZE);
const tag = bytes.subarray(-TAG_SIZE);
const decipher = createDecipheriv('aes-256-gcm', this.key, nonce);
decipher.setAuthTag(tag);
return Buffer.concat([
decipher.update(bytes.subarray(VERSION_SIZE_BYTES + NONCE_SIZE, -TAG_SIZE)),
decipher.final(),
]).toString('utf8');
}
}