Carry file size, thumbnail size, and deletion flag through decryptFile (closes #37)
check / check (push) Successful in 25s
check / check (push) Successful in 25s
Foundation unit for the cache/API design. Three fields arrived on the wire but decryptFile dropped them: - `file.size` from `info.fileSize` and `thumbnail.size` from `info.thumbSize`, left `undefined` when the server omits `info`. - `isDeleted` carried from the diff row onto `EnteFile`. No caller change: `listFiles` still filters deleted rows before decrypt, so no deleted row reaches decryptFile here. Surfacing a deleted file through decryption belongs to the enumeration unit, issue 38, where the return shape can be designed around where such a row actually flows. Model: opus-4-8
This commit is contained in:
@@ -145,7 +145,12 @@ const buildSharedRawCollection = (
|
||||
|
||||
const buildRawFile = (
|
||||
collectionKey: Uint8Array,
|
||||
opts?: { title?: string; fileType?: number; creationTime?: number },
|
||||
opts?: {
|
||||
title?: string;
|
||||
fileType?: number;
|
||||
creationTime?: number;
|
||||
info?: { fileSize?: number; thumbSize?: number };
|
||||
},
|
||||
): RawEnteFile => {
|
||||
const fileKey = sodium.crypto_secretbox_keygen();
|
||||
const { ciphertext: encFileKey, nonce: fileKeyNonce } = secretboxEncrypt(
|
||||
@@ -186,6 +191,7 @@ const buildRawFile = (
|
||||
},
|
||||
file: { decryptionHeader: toBase64(sodium.randombytes_buf(24)) },
|
||||
thumbnail: { decryptionHeader: toBase64(sodium.randombytes_buf(24)) },
|
||||
info: opts?.info,
|
||||
updationTime: 1700000000000000,
|
||||
};
|
||||
};
|
||||
@@ -357,4 +363,47 @@ describe("model.decryptFile", () => {
|
||||
|
||||
expect(() => decryptFile(raw, wrongKey)).toThrow();
|
||||
});
|
||||
|
||||
it("carries the file and thumbnail byte sizes from info", () => {
|
||||
// The server reports the encrypted-blob sizes in `info`; the cache
|
||||
// needs them without a HEAD request, so decryptFile must copy them
|
||||
// onto the file and thumbnail blobs.
|
||||
const masterKey = sodium.crypto_secretbox_keygen();
|
||||
const { collectionKey } = buildRawCollection(masterKey);
|
||||
const raw = buildRawFile(collectionKey, {
|
||||
info: { fileSize: 4096, thumbSize: 512 },
|
||||
});
|
||||
|
||||
const file = decryptFile(raw, collectionKey);
|
||||
|
||||
expect(file.file.size).toBe(4096);
|
||||
expect(file.thumbnail.size).toBe(512);
|
||||
});
|
||||
|
||||
it("leaves the sizes undefined when the server omits info", () => {
|
||||
// Older files predate the info field; the sizes must stay undefined
|
||||
// rather than become 0, so callers can tell "unknown" from "empty".
|
||||
const masterKey = sodium.crypto_secretbox_keygen();
|
||||
const { collectionKey } = buildRawCollection(masterKey);
|
||||
const raw = buildRawFile(collectionKey);
|
||||
expect(raw.info).toBeUndefined();
|
||||
|
||||
const file = decryptFile(raw, collectionKey);
|
||||
|
||||
expect(file.file.size).toBeUndefined();
|
||||
expect(file.thumbnail.size).toBeUndefined();
|
||||
});
|
||||
|
||||
it("carries the deletion flag from the diff row", () => {
|
||||
// The diff marks a deleted row with isDeleted; decryptFile copies it
|
||||
// onto the file so a caller can tell a deleted row from a live one.
|
||||
const masterKey = sodium.crypto_secretbox_keygen();
|
||||
const { collectionKey } = buildRawCollection(masterKey);
|
||||
const raw = buildRawFile(collectionKey);
|
||||
raw.isDeleted = true;
|
||||
|
||||
const file = decryptFile(raw, collectionKey);
|
||||
|
||||
expect(file.isDeleted).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user