import { describe, it, expect } from 'vitest'; import { encrypt_api_key, decrypt_api_key, maybe_encrypt_api_key, is_encrypted_api_key, } from '../../../src/nest/common/crypto/apiKeyCrypto'; describe('apiKeyCrypto', () => { const PLAINTEXT_KEY = 'my-secret-api-key-12345'; const ENC_PREFIX = 'enc:v1:'; // SEC-008 — Encrypted API keys not returned in plaintext describe('encrypt_api_key', () => { it('SEC-008: returns encrypted string with enc:v1: prefix', () => { const encrypted = encrypt_api_key(PLAINTEXT_KEY); expect(encrypted).toMatch(/^enc:v1:/); }); it('different calls produce different ciphertext (random IV)', () => { const enc1 = encrypt_api_key(PLAINTEXT_KEY); const enc2 = encrypt_api_key(PLAINTEXT_KEY); expect(enc1).not.toBe(enc2); }); it('encrypted value does not contain the plaintext', () => { const encrypted = encrypt_api_key(PLAINTEXT_KEY); expect(encrypted).not.toContain(PLAINTEXT_KEY); }); }); describe('decrypt_api_key', () => { it('SEC-008: decrypts an encrypted key back to original', () => { const encrypted = encrypt_api_key(PLAINTEXT_KEY); const decrypted = decrypt_api_key(encrypted); expect(decrypted).toBe(PLAINTEXT_KEY); }); it('returns null for null input', () => { expect(decrypt_api_key(null)).toBeNull(); }); it('returns null for empty string', () => { expect(decrypt_api_key('')).toBeNull(); }); it('returns plaintext as-is if not prefixed (legacy)', () => { expect(decrypt_api_key('plain-legacy-key')).toBe('plain-legacy-key'); }); it('returns null for tampered ciphertext', () => { const encrypted = encrypt_api_key(PLAINTEXT_KEY); const tampered = encrypted.replace(ENC_PREFIX, ENC_PREFIX) + 'TAMPER'; expect(decrypt_api_key(tampered)).toBeNull(); }); }); describe('maybe_encrypt_api_key', () => { it('encrypts a new plaintext value', () => { const result = maybe_encrypt_api_key('my-key'); expect(result).toMatch(/^enc:v1:/); }); it('returns null for empty/falsy values', () => { expect(maybe_encrypt_api_key('')).toBeNull(); expect(maybe_encrypt_api_key(null)).toBeNull(); expect(maybe_encrypt_api_key(undefined)).toBeNull(); }); it('returns already-encrypted value as-is (no double-encryption)', () => { const encrypted = encrypt_api_key(PLAINTEXT_KEY); const result = maybe_encrypt_api_key(encrypted); expect(result).toBe(encrypted); }); }); describe('is_encrypted_api_key', () => { it('is true exactly for enc:v1: envelopes', () => { expect(is_encrypted_api_key(encrypt_api_key('s'))).toBe(true); expect(is_encrypted_api_key('enc:v1:AAAA')).toBe(true); expect(is_encrypted_api_key('plaintext')).toBe(false); expect(is_encrypted_api_key('')).toBe(false); expect(is_encrypted_api_key(null)).toBe(false); expect(is_encrypted_api_key(42)).toBe(false); }); }); });