import { describe, expect, it } from 'vitest'; import { decryptInvitation, encryptInvitation, generateInvitationKeys, openJson, sealJson } from './accountCrypto'; describe('encrypted invitation recipient binding', () => { it('only the addressed account and channel can decrypt the member link', async () => { const bob = await generateInvitationKeys(); const carol = await generateInvitationKeys(); const payload = await encryptInvitation('https://drop.test/c/channel#k=secret', 'bob', 'channel', bob.publicKey); expect(payload).not.toContain('secret'); expect(await decryptInvitation(payload, 'bob', 'channel', bob.privateKey)).toContain('#k=secret'); await expect(decryptInvitation(payload, 'carol', 'channel', carol.privateKey)).rejects.toThrow(); await expect(decryptInvitation(payload, 'bob', 'other-channel', bob.privateKey)).rejects.toThrow(); }); it('modified encrypted vault contents are rejected', async () => { const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']); const encrypted = await sealJson({ resources: [] }, key); const raw = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0)); raw[13] = (raw[13] ?? 0) ^ 1; const corrupted = btoa(String.fromCharCode(...raw)); await expect(openJson(corrupted, key)).rejects.toThrow('校验失败'); }); });