Carry file size, thumbnail size, and deletion flag through file decryption #37

Closed
opened 2026-09-22 09:10:56 +02:00 by clawbot · 1 comment
Collaborator

Foundation unit for the cache/API design (#36). This
is the first piece; everything later needs it, so it lands first.

Goal

Carry three fields that arrive on the wire but are dropped at decryption, so the
metadata cache, the plain records, and the download/integrity code can see them:

  • info.fileSize and info.thumbSize (bytes on the wire), and
  • isDeleted (the tombstone flag).

Current state (grounded)

  • RawEnteFile already declares info?: { fileSize?; thumbSize? } and
    isDeleted? (src/model/types.ts), but decryptFile (src/model/decrypt.ts)
    copies neither into the returned EnteFile.
  • EnteFile.file/EnteFile.thumbnail are FileBlob { decryptionHeader; size? }
    size exists on the type but is never populated.

Scope (extend existing; no new modules)

  • In decryptFile, set file.size = raw.info?.fileSize and
    thumbnail.size = raw.info?.thumbSize (leave undefined when the server
    omits them — do not coerce to 0).
  • Surface the tombstone on the decrypted record. Add isDeleted?: boolean to
    EnteFile and set it from raw.isDeleted. decryptFile currently assumes a
    live row; a tombstone row may lack the fields needed to decrypt
    (encryptedKey, metadata). So: when raw.isDeleted is true, return a
    minimal EnteFile carrying id, collectionID, updationTime, and
    isDeleted: true, without attempting decryption. Confirm the exact tombstone
    shape against the test fixtures before deciding which fields are safe to read.
  • Do not change any caller behaviour in this unit. Client.listFiles today
    filters isDeleted before calling decryptFile, so it never passes a
    tombstone in; that path is unchanged here and is reworked in the enumeration
    unit.

Definition of done

  • decryptFile populates file.size, thumbnail.size, and isDeleted.
  • A live-file fixture yields the sizes; a tombstone fixture yields
    { id, collectionID, updationTime, isDeleted: true } and does not throw.
  • New/extended tests in test/model/decrypt.test.ts cover both cases,
    including the size-absent case (stays undefined).
  • make check green. No behaviour change for existing callers.

Grounding

Files: src/model/types.ts, src/model/decrypt.ts, test/model/decrypt.test.ts.

Dispatch notes for the implementer: TDD (red test first). No scripted edits —
read and hand-edit; format only via make fmt. Do not ask interactive
questions; decide from this brief and the fixtures. Land the squash commit
subject ending (closes #<this issue>). Every commit message, PR body, and
comment ends with Model: opus-4-8.

Model: opus-4-8

Foundation unit for the cache/API design (https://git.eeqj.de/sneak/quak/issues/36). This is the first piece; everything later needs it, so it lands first. ## Goal Carry three fields that arrive on the wire but are dropped at decryption, so the metadata cache, the plain records, and the download/integrity code can see them: - `info.fileSize` and `info.thumbSize` (bytes on the wire), and - `isDeleted` (the tombstone flag). ## Current state (grounded) - `RawEnteFile` already declares `info?: { fileSize?; thumbSize? }` and `isDeleted?` (`src/model/types.ts`), but `decryptFile` (`src/model/decrypt.ts`) copies neither into the returned `EnteFile`. - `EnteFile.file`/`EnteFile.thumbnail` are `FileBlob { decryptionHeader; size? }` — `size` exists on the type but is never populated. ## Scope (extend existing; no new modules) - In `decryptFile`, set `file.size = raw.info?.fileSize` and `thumbnail.size = raw.info?.thumbSize` (leave `undefined` when the server omits them — do not coerce to 0). - Surface the tombstone on the decrypted record. Add `isDeleted?: boolean` to `EnteFile` and set it from `raw.isDeleted`. `decryptFile` currently assumes a live row; a tombstone row may lack the fields needed to decrypt (`encryptedKey`, `metadata`). So: when `raw.isDeleted` is true, return a minimal `EnteFile` carrying `id`, `collectionID`, `updationTime`, and `isDeleted: true`, without attempting decryption. Confirm the exact tombstone shape against the test fixtures before deciding which fields are safe to read. - Do not change any caller behaviour in this unit. `Client.listFiles` today filters `isDeleted` before calling `decryptFile`, so it never passes a tombstone in; that path is unchanged here and is reworked in the enumeration unit. ## Definition of done - `decryptFile` populates `file.size`, `thumbnail.size`, and `isDeleted`. - A live-file fixture yields the sizes; a tombstone fixture yields `{ id, collectionID, updationTime, isDeleted: true }` and does not throw. - New/extended tests in `test/model/decrypt.test.ts` cover both cases, including the size-absent case (stays `undefined`). - `make check` green. No behaviour change for existing callers. ## Grounding Files: `src/model/types.ts`, `src/model/decrypt.ts`, `test/model/decrypt.test.ts`. Dispatch notes for the implementer: TDD (red test first). No scripted edits — read and hand-edit; format only via `make fmt`. Do not ask interactive questions; decide from this brief and the fixtures. Land the squash commit subject ending ` (closes #<this issue>)`. Every commit message, PR body, and comment ends with `Model: opus-4-8`. Model: opus-4-8
Author
Collaborator

Implemented in PR #55.

decryptFile now carries file.size/thumbnail.size from the server's info
(left undefined when omitted), and returns a minimal tombstone for a deleted
file without decrypting.

One design call worth your eye: rather than making EnteFile's structural
fields optional (which breaks every consumer under strict tsc), a tombstone is a
distinct EnteFileTombstone type and decryptFile returns
EnteFile | EnteFileTombstone. Details and disclosures are in the PR body.

Model: opus-4-8

Implemented in [PR #55](https://git.eeqj.de/sneak/quak/pulls/55). `decryptFile` now carries `file.size`/`thumbnail.size` from the server's `info` (left `undefined` when omitted), and returns a minimal tombstone for a deleted file without decrypting. One design call worth your eye: rather than making `EnteFile`'s structural fields optional (which breaks every consumer under strict tsc), a tombstone is a distinct `EnteFileTombstone` type and `decryptFile` returns `EnteFile | EnteFileTombstone`. Details and disclosures are in the PR body. Model: opus-4-8
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/quak#37