import test from "node:test"; import assert from "node:assert/strict"; import { loadModule } from "./test-helpers.mjs"; const crypto = await loadModule("app/utils/crypto.ts"); const id = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; const key = crypto.generateKey(); const wrongKey = crypto.generateKey(); const nonce = crypto.generateNoncePrefix(); test("AES-GCM manifest and chunk round trips preserve plaintext", async () => { const plain = new TextEncoder().encode("hello chunk"); const cipher = await crypto.encryptChunk( plain, key, id, nonce, 0, 8 * 1024 * 1024, 1, ); assert.deepEqual( [ ...(await crypto.decryptChunk( cipher, key, id, nonce, 0, plain.byteLength, 8 * 1024 * 1024, 1, )), ], [...plain], ); const manifest = { version: 2, name: "hello.txt", type: "text/plain", size: plain.byteLength, lastModified: 1, chunkSize: 8 * 1024 * 1024, chunkCount: 1, }; const encrypted = await crypto.encryptManifest(manifest, key, id, nonce); assert.deepEqual( await crypto.decryptManifest( encrypted, key, id, nonce, manifest.chunkSize, manifest.chunkCount, ), manifest, ); }); test("empty chunks are authenticated and round-trip", async () => { const cipher = await crypto.encryptChunk( new Uint8Array(), key, id, nonce, 0, 8 * 1024 * 1024, 1, ); assert.equal(cipher.byteLength, 16); assert.equal( ( await crypto.decryptChunk( cipher, key, id, nonce, 0, 0, 8 * 1024 * 1024, 1, ) ).byteLength, 0, ); }); test("tampering and wrong key or AAD fail integrity", async () => { const cipher = await crypto.encryptChunk( new Uint8Array([1, 2, 3]), key, id, nonce, 0, 8 * 1024 * 1024, 1, ); const tampered = new Uint8Array(cipher); tampered[0] ^= 1; await assert.rejects( crypto.decryptChunk(tampered, key, id, nonce, 0, 3, 8 * 1024 * 1024, 1), /integrity/, ); await assert.rejects( crypto.decryptChunk(cipher, wrongKey, id, nonce, 0, 3, 8 * 1024 * 1024, 1), /integrity/, ); await assert.rejects( crypto.decryptChunk(cipher, key, id, nonce, 1, 3, 8 * 1024 * 1024, 1), /integrity/, ); }); test("tag-only manifests are rejected before decryption", async () => { await assert.rejects( crypto.decryptManifest( new Uint8Array(16), key, id, nonce, 8 * 1024 * 1024, 1, ), /empty/, ); });