import { describe, expect, it } from "@suaveplan/testing/runner"; import { VAULT_CODES } from "../errors/codes.js"; import { VaultError } from "../errors/vault-error.js"; import type { CreatedShareLink, CreateShareLinkInput, DriveSharingLike, } from "../types/adapters.js"; import type { ShareLink } from "../types/types.js"; import { VaultShares } from "./shares.js"; function vaultKey(): Uint8Array { const key = new Uint8Array(32); crypto.getRandomValues(key); return key; } class StubDriveSharing implements DriveSharingLike { public received: CreateShareLinkInput[] = []; public revoked: string[] = []; public failOn: "create" | "revoke" | undefined; public counter = 0; public async createLink( input: CreateShareLinkInput ): Promise { if (this.failOn === "create") throw new Error("offline"); this.received.push(input); this.counter += 1; const id = `share-${this.counter}`; return { id, url: `https://share.example/${id}` }; } public async revokeLink(id: string): Promise { if (this.failOn === "revoke") throw new Error("offline"); this.revoked.push(id); } public async isActive(id: string): Promise { return !this.revoked.includes(id); } } function makeShares(driveSharing?: DriveSharingLike): { shares: VaultShares; driveSharing: StubDriveSharing; metadata: Map; } { const stub = (driveSharing as StubDriveSharing | undefined) ?? new StubDriveSharing(); const metadata = new Map(); const shares = new VaultShares({ driveSharing: stub, partitionId: "part-1", vaultKey: vaultKey(), clock: () => 1, rng: undefined, metadata, onMutation: () => {}, }); return { shares, driveSharing: stub, metadata }; } describe("VaultShares", () => { it("createLink wraps the plaintext and returns metadata", { timeout: 5000, }, async () => { const { shares, driveSharing } = makeShares(); const link = await shares.createLink({ itemId: "i1", itemPlaintext: new TextEncoder().encode("payload"), expiresAt: 99, maxViews: 5, }); expect(link.id).toBe("share-1"); expect(link.url).toContain("share-1"); expect(driveSharing.received[0]?.partitionId).toBe("part-1"); expect(driveSharing.received[0]?.wrappedKey.length).toBeGreaterThan(0); }); it("createLink wraps drive failures as DRIVE.FAILURE", { timeout: 5000, }, async () => { const stub = new StubDriveSharing(); stub.failOn = "create"; const { shares } = makeShares(stub); try { await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe(VAULT_CODES["DRIVE.FAILURE"]); } }); it("revokeLink removes local metadata", { timeout: 5000 }, async () => { const { shares, driveSharing, metadata } = makeShares(); const link = await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); await shares.revokeLink(link.id); expect(metadata.has(link.id)).toBe(false); expect(driveSharing.revoked).toEqual([link.id]); }); it("revokeLink throws SHARE.NOT_FOUND on unknown ids", { timeout: 5000, }, async () => { const { shares } = makeShares(); try { await shares.revokeLink("missing"); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe( VAULT_CODES["SHARE.NOT_FOUND"] ); } }); it("revokeLink wraps drive failures as DRIVE.FAILURE", { timeout: 5000, }, async () => { const stub = new StubDriveSharing(); const { shares } = makeShares(stub); const link = await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); stub.failOn = "revoke"; try { await shares.revokeLink(link.id); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe(VAULT_CODES["DRIVE.FAILURE"]); } }); it("isActive short-circuits when local metadata is missing", { timeout: 5000, }, async () => { const { shares } = makeShares(); expect(await shares.isActive("missing")).toBe(false); }); it("isActive returns the canonical answer from drive-sharing", { timeout: 5000, }, async () => { const { shares } = makeShares(); const link = await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); expect(await shares.isActive(link.id)).toBe(true); await shares.revokeLink(link.id); // After revoke, metadata is removed locally; isActive returns false. expect(await shares.isActive(link.id)).toBe(false); }); it("list returns all known share metadata", { timeout: 5000 }, async () => { const { shares } = makeShares(); await shares.createLink({ itemId: "a", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); await shares.createLink({ itemId: "b", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); expect(shares.list().length).toBe(2); }); it("createLink with an injected RNG produces deterministic wrappedKey nonces", { timeout: 5000, }, async () => { const stub = new StubDriveSharing(); const metadata = new Map(); const rng = { nextUint32: () => 1, nextFloat: () => 0, nextBytes: (len: number) => new Uint8Array(len).fill(2), }; const shares = new VaultShares({ driveSharing: stub, partitionId: "p", vaultKey: new Uint8Array(32), clock: () => 0, rng, metadata, onMutation: () => {}, }); await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); const wrapped = stub.received[0]?.wrappedKey as Uint8Array; expect(wrapped.slice(0, 24)).toEqual(new Uint8Array(24).fill(2)); }); it("non-Error createLink failures still surface as DRIVE.FAILURE", { timeout: 5000, }, async () => { const sentinel: unknown = "non-error"; class BadStub extends StubDriveSharing { public override async createLink(): Promise { throw sentinel; } } const stub = new BadStub(); const { shares } = makeShares(stub); try { await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe(VAULT_CODES["DRIVE.FAILURE"]); } }); it("non-Error revokeLink failures still surface as DRIVE.FAILURE", { timeout: 5000, }, async () => { const sentinel: unknown = "non-error"; class BadStub extends StubDriveSharing { public override async revokeLink(): Promise { throw sentinel; } } const stub = new BadStub(); const { shares } = makeShares(stub); const link = await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); try { await shares.revokeLink(link.id); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe(VAULT_CODES["DRIVE.FAILURE"]); } }); it("createLink validates the produced ShareLink", { timeout: 5000, }, async () => { class BadStub extends StubDriveSharing { public override async createLink( _input: CreateShareLinkInput ): Promise { return { id: "x", url: "not-a-url" }; } } const stub = new BadStub(); const { shares } = makeShares(stub); try { await shares.createLink({ itemId: "i", itemPlaintext: new Uint8Array(1), expiresAt: null, maxViews: null, }); throw new Error("should have thrown"); } catch (err) { expect(VaultError.is(err)).toBe(true); expect((err as VaultError).code).toBe( VAULT_CODES["ITEM.VALIDATION_FAILED"] ); } }); });