Files
quickdrop/tests/drop-crypto.test.mjs
2026-08-07 22:13:25 -05:00

127 lines
2.6 KiB
JavaScript

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/,
);
});