import { describe, expect, it } from "@suaveplan/testing/runner"; import { CRYPTO_RSA_CODES, type CryptoRsaError } from "../errors/errors.js"; import type { RsaKeyHandle, RsaKeyHandleProvider } from "./handle.types.js"; import { decryptWithHandle, registerKeyHandleProvider, resolveKeyHandle, signWithHandle, unregisterKeyHandleProvider, } from "./registry.js"; function makeStubProvider(name: string): RsaKeyHandleProvider { return { name, async resolve(_handle: RsaKeyHandle) { return { n: 1n, e: 3n, bitLength: 1 }; }, async sign(_handle, _message, _options) { return new Uint8Array([0xab]); }, async decrypt(_handle, _ciphertext, _options) { return new Uint8Array([0xcd]); }, }; } describe("registerKeyHandleProvider + resolveKeyHandle", () => { it("registers a provider and resolves a handle", { timeout: 5000, }, async () => { const provider = makeStubProvider("stub-resolve"); registerKeyHandleProvider(provider); try { const handle: RsaKeyHandle = { provider: "stub-resolve", id: "k1", }; const resolved = await resolveKeyHandle(handle); expect(resolved.n).toBe(1n); } finally { unregisterKeyHandleProvider("stub-resolve"); } }); it("idempotent re-registration of the same provider value", { timeout: 5000, }, () => { const provider = makeStubProvider("stub-idem"); registerKeyHandleProvider(provider); registerKeyHandleProvider(provider); unregisterKeyHandleProvider("stub-idem"); }); it("conflicting registration of a different provider rejects with INVALID_KEY", { timeout: 5000, }, () => { const a = makeStubProvider("stub-conflict"); const b = makeStubProvider("stub-conflict"); registerKeyHandleProvider(a); try { try { registerKeyHandleProvider(b); throw new Error("should have thrown"); } catch (err) { expect((err as CryptoRsaError).code).toBe( CRYPTO_RSA_CODES.INVALID_KEY ); } } finally { unregisterKeyHandleProvider("stub-conflict"); } }); it("resolves missing-provider lookup with INVALID_KEY", { timeout: 5000, }, async () => { const handle: RsaKeyHandle = { provider: "nonexistent", id: "x", }; try { await resolveKeyHandle(handle); throw new Error("should have thrown"); } catch (err) { expect((err as CryptoRsaError).code).toBe( CRYPTO_RSA_CODES.INVALID_KEY ); } }); it("signWithHandle delegates to the provider", { timeout: 5000, }, async () => { const provider = makeStubProvider("stub-sign"); registerKeyHandleProvider(provider); try { const handle: RsaKeyHandle = { provider: "stub-sign", id: "k1", }; const sig = await signWithHandle(handle, new Uint8Array([1, 2]), { scheme: "pkcs1v15", hash: "SHA-256", }); expect(sig[0]).toBe(0xab); } finally { unregisterKeyHandleProvider("stub-sign"); } }); it("decryptWithHandle delegates to the provider", { timeout: 5000, }, async () => { const provider = makeStubProvider("stub-decrypt"); registerKeyHandleProvider(provider); try { const handle: RsaKeyHandle = { provider: "stub-decrypt", id: "k1", }; const pt = await decryptWithHandle(handle, new Uint8Array([1, 2]), { scheme: "oaep", hash: "SHA-256", }); expect(pt[0]).toBe(0xcd); } finally { unregisterKeyHandleProvider("stub-decrypt"); } }); });