Add failing tests for download truncation detection and atomic writes
Covers, for both downloadFile and downloadThumbnail: - a multi-chunk body whose TAG_FINAL chunk never arrived is rejected with a truncation error; - an empty body is rejected as truncation rather than written as a zero-byte file; - after a truncation or chunk-authentication failure the destination path does not exist and no temporary scratch file is left behind; - an existing file at the destination survives a failed download byte for byte, and is replaced atomically by a successful one; - the existing success cases still produce identical bytes and an identical DownloadResult. Adds an encryptMultiChunkBody helper that frames leading chunks at exactly STREAM_CHUNK_SIZE so the downloader's fixed-size re-splitting lines up, plus a multi-chunk success case as the positive control. Also pins the new STREAM_TAG_FINAL crypto export against libsodium's own constant, since it must be declared as a literal: libsodium attaches its constants only after sodium.ready resolves, well after this library's modules are evaluated. These fail until the implementation lands, per the repo's TDD workflow.
This commit is contained in:
@@ -15,7 +15,8 @@
|
||||
* stream ended on a `TAG_FINAL` chunk and was therefore not truncated.
|
||||
*
|
||||
* These tests pin:
|
||||
* - The chunk-size constants match Ente's expectations.
|
||||
* - The chunk-size constants match Ente's expectations, and the
|
||||
* re-exported `STREAM_TAG_FINAL` matches libsodium's own constant.
|
||||
* - The pull state can decrypt a multi-chunk stream produced by
|
||||
* sodium.crypto_secretstream_xchacha20poly1305_push, in order.
|
||||
* - The tag byte is propagated to the caller.
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
pullStreamChunk,
|
||||
STREAM_CHUNK_OVERHEAD,
|
||||
STREAM_CHUNK_SIZE,
|
||||
STREAM_TAG_FINAL,
|
||||
} from "../../src/crypto/index.js";
|
||||
|
||||
describe("crypto stream constants", () => {
|
||||
@@ -45,6 +47,22 @@ describe("crypto stream constants", () => {
|
||||
it("STREAM_CHUNK_OVERHEAD is 17 bytes", () => {
|
||||
expect(STREAM_CHUNK_OVERHEAD).toBe(17);
|
||||
});
|
||||
|
||||
/**
|
||||
* `STREAM_TAG_FINAL` is re-exported so callers can detect a truncated
|
||||
* stream (a body that ended on a non-final chunk) without importing
|
||||
* libsodium themselves. It has to be declared as a literal, because
|
||||
* libsodium only attaches its own constants to the module object after
|
||||
* `sodium.ready` resolves — long after this library's modules are
|
||||
* evaluated. This test is what keeps the literal honest.
|
||||
*/
|
||||
it("STREAM_TAG_FINAL equals libsodium's TAG_FINAL", async () => {
|
||||
await init();
|
||||
await sodium.ready;
|
||||
expect(STREAM_TAG_FINAL).toBe(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("crypto.initStreamPull / pullStreamChunk", () => {
|
||||
|
||||
Reference in New Issue
Block a user