Files
WebDrop/web/src/core-bridge/worker/accountVault.test.ts
T

29 lines
1.9 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { exportResource, mergeVault, type VaultProfile } from './accountVault';
import type { SavedResource } from '../database';
const resource = (modifiedAt = 10): SavedResource => ({ id: 'AAAAAAAAAAAAAAAAAAAAAA', kind: 'channel', mode: 'enc', role: 'owner',
link: 'https://drop.test/c/a#k=secret', endpointSecret: new Uint8Array(32).fill(7), deviceLabel: 'device-a', localScope: 'account:alice',
createdAt: 1, modifiedAt, expiresAt: 100, seats: 3, name: `version-${modifiedAt}` });
const profile = (): VaultProfile => ({ v: 3, keys: { publicKey: {}, privateKey: {}, signing: { publicKey: {}, privateKey: {} } }, resources: [exportResource(resource(20))], deletes: [] });
describe('account vault portability and merge', () => {
it('never synchronizes device identity or local scope', () => {
const exported = exportResource(resource());
expect(exported).not.toHaveProperty('endpointSecret'); expect(exported).not.toHaveProperty('deviceLabel');
expect(exported).not.toHaveProperty('localScope'); expect(exported.link).toContain('secret');
});
it('a stale device does not overwrite a newer remote resource', () => {
expect(mergeVault(profile(), [resource(10)], []).resources[0]?.name).toBe('version-20');
});
it('resource removal survives a stale device syncing its old copy', () => {
const remote = { ...profile(), resources: [], deletes: [{ id: resource().id, modifiedAt: 30 }] };
expect(mergeVault(remote, [resource(20)], []).resources).toEqual([]);
expect(mergeVault(profile(), [], [{ id: resource().id, modifiedAt: 30 }]).resources).toEqual([]);
});
it('explicitly rejoining after removal restores the resource', () => {
const remote = { ...profile(), resources: [], deletes: [{ id: resource().id, modifiedAt: 30 }] };
const merged = mergeVault(remote, [resource(40)], []);
expect(merged.resources).toHaveLength(1); expect(merged.deletes).toEqual([]);
});
});