diff --git a/apps/web/__tests__/vault-validation.test.js b/apps/web/__tests__/vault-validation.test.js new file mode 100644 index 0000000..983d1d5 --- /dev/null +++ b/apps/web/__tests__/vault-validation.test.js @@ -0,0 +1,155 @@ +/** + * Tests for vault payload validation. + * + * The server cannot inspect what it stores, so these checks are the entire + * defence against a malformed or hostile write reaching the table. The + * KDF-floor case matters most: it stops one client creating a weak vault that + * every other client then has to open. + * @module __tests__/vault-validation.test + */ + +import { describe, it, expect } from 'vitest'; +import { + isUuid, + isSaneBlob, + validateItemPayload, + validateVaultMeta, + MAX_CIPHERTEXT_LENGTH, + MIN_KDF_ITERATIONS, +} from '@/lib/vault-validation'; + +const validItem = () => ({ + id: '3f2504e0-4f89-41d3-9a0c-0305e82c3301', + type: 1, + ciphertext: 'aGVsbG8gd29ybGQ=', + iv: 'YWJjZGVmZ2hpams=', +}); + +const validMeta = () => ({ + kdf: 'pbkdf2-sha256', + iterations: 600000, + salt: 'c2FsdHNhbHQ=', + protectedUserKey: 'a2V5', + protectedUserKeyIv: 'aXY=', + authHash: 'aGFzaA==', +}); + +describe('isUuid', () => { + it('accepts a v4 uuid', () => { + expect(isUuid('3f2504e0-4f89-41d3-9a0c-0305e82c3301')).toBe(true); + }); + + it.each([['not-a-uuid'], [''], [null], [42], ['3f2504e04f8941d39a0c0305e82c3301']])( + 'rejects %s', + (value) => { + expect(isUuid(value)).toBe(false); + } + ); +}); + +describe('isSaneBlob', () => { + it('accepts base64', () => { + expect(isSaneBlob('aGVsbG8=')).toBe(true); + }); + + it('rejects non-base64 characters', () => { + expect(isSaneBlob('not base64!')).toBe(false); + expect(isSaneBlob('