import { test, expect } from "bun:test"; import { generateKey, encrypt, decrypt, deriveKey, sha256, hmacSign, hmacVerify, createKeyring, } from "../src/index.ts"; test("sha256 is stable and hex-encoded", async () => { const a = await sha256("hello"); expect(a).toBe("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"); expect(await sha256("hello")).toBe(a); expect(await sha256("world")).not.toBe(a); }); test("hmacSign / hmacVerify (webhook signatures)", async () => { const sig = await hmacSign("payload", "secret"); expect(await hmacVerify("payload", "secret", sig)).toBe(true); expect(await hmacVerify("payload", "wrong", sig)).toBe(false); expect(await hmacVerify("tampered", "secret", sig)).toBe(false); }); test("encrypt/decrypt round-trip", async () => { const key = await generateKey(); const box = await encrypt("card #1234 secret", key); expect(box).not.toContain("card"); // opaque expect(await decrypt(box, key)).toBe("card #1234 secret"); }); test("each encryption uses a fresh IV (different ciphertexts)", async () => { const key = await generateKey(); const a = await encrypt("same", key); const b = await encrypt("same", key); expect(a).not.toBe(b); expect(await decrypt(a, key)).toBe("same"); expect(await decrypt(b, key)).toBe("same"); }); test("wrong key or tampered data fails (authenticated)", async () => { const key = await generateKey(); const other = await generateKey(); const box = await encrypt("secret", key); await expect(decrypt(box, other)).rejects.toThrow(); await expect(decrypt(box.slice(0, -4) + "AAAA", key)).rejects.toThrow(); }); test("deriveKey is deterministic for the same password+salt", async () => { const k1 = await deriveKey("hunter2", "user-salt"); const k2 = await deriveKey("hunter2", "user-salt"); const k3 = await deriveKey("hunter2", "other-salt"); expect(k1).toBe(k2); expect(k1).not.toBe(k3); // usable as an encryption key expect(await decrypt(await encrypt("x", k1), k1)).toBe("x"); }); test("keyrings reject duplicate keys and return defensive copies", () => { expect(() => createKeyring([ { id: "one", secret: "secret-one", active: true }, { id: "one", secret: "secret-two" }, ]), ).toThrow("DUPLICATE"); const keyring = createKeyring([ { id: "one", secret: "secret-one", active: true }, { id: "two", secret: "secret-two" }, ]); const active = keyring.active(); active.secret = "changed"; expect(keyring.active().secret).toBe("secret-one"); });