/** * Unit tests for src/utils/crypto.ts */ import { generateClientSecret, hashSecret, verifySecret } from '../../../src/utils/crypto'; describe('crypto utils', () => { describe('generateClientSecret()', () => { it('should return a string starting with sk_live_', () => { const secret = generateClientSecret(); expect(secret).toMatch(/^sk_live_/); }); it('should return 64 hex chars after the prefix', () => { const secret = generateClientSecret(); const hex = secret.slice('sk_live_'.length); expect(hex).toHaveLength(64); expect(hex).toMatch(/^[0-9a-f]{64}$/); }); it('should generate unique secrets on each call', () => { const secret1 = generateClientSecret(); const secret2 = generateClientSecret(); expect(secret1).not.toBe(secret2); }); it('should have total length of 72 characters (8 + 64)', () => { const secret = generateClientSecret(); expect(secret).toHaveLength(72); }); }); describe('hashSecret() and verifySecret()', () => { it('should hash a secret and verify it correctly', async () => { const plain = generateClientSecret(); const hash = await hashSecret(plain); const isValid = await verifySecret(plain, hash); expect(isValid).toBe(true); }); it('should return false for a wrong secret', async () => { const plain = generateClientSecret(); const hash = await hashSecret(plain); const isValid = await verifySecret('wrong_secret', hash); expect(isValid).toBe(false); }); it('should produce different hashes for the same input (salt randomness)', async () => { const plain = generateClientSecret(); const hash1 = await hashSecret(plain); const hash2 = await hashSecret(plain); expect(hash1).not.toBe(hash2); }); it('should produce a bcrypt hash string', async () => { const plain = generateClientSecret(); const hash = await hashSecret(plain); // bcrypt hashes start with $2a$ or $2b$ expect(hash).toMatch(/^\$2[ab]\$/); }); }); });