19 tests covering ApiClient's full public surface: default and custom
origins, X-Client-Package and X-Auth-Token headers, getJSON with query
params, postJSON with JSON body, ApiError on 4xx/5xx, streaming file
and thumbnail downloads, and self-hosted origin routing.
Tests inject a recording fetch via the constructor, so nothing hits the
network. The test file is documented to serve as canonical usage
reference per the development workflow.
unwrapAuth: password to master/secret/public key and auth token. The
password-only side of Ente login. Built test-first; 6 tests describe
the protocol and verify byte-for-byte recovery of the inputs from a
synthetic AuthorizationResponse.
The implementation is exactly the decryption chain documented in the
test file: deriveKEK -> decryptBox(masterKey) -> decryptBox(secretKey)
-> decryptSealed(token) -> toBase64URL. Errors from the underlying
crypto primitives propagate; the only added validation is the up-front
check that the response actually contains both keyAttributes and
encryptedToken (caller bug if not).
Also re-exports the auth/unwrap and auth/types public surface from
src/index.ts.
All 38 tests pass; make check and make docker are green.
Tests for the password-only decryption chain that follows a successful
login (SRP or email OTP, with or without 2FA). The unwrap covers:
password -> KEK (Argon2id) -> masterKey (secretbox) ->
secretKey (secretbox) -> tokenBytes (sealed box) -> base64url token
Each test builds a synthetic AuthorizationResponse using libsodium
directly and asserts unwrapAuth recovers the inputs byte for byte. The
test file also functions as the canonical description of the protocol.
Adds src/auth/types.ts with KeyAttributes, SRPAttributes,
AuthorizationResponse, and LoginChallenge declarations matching the
README's API reference. src/auth/unwrap.ts is the throwing stub; the
real implementation lands next.
Implements all the libsodium primitives quack needs to unwrap key
material and decrypt files (KDF, secretbox, sealed box, secretstream
pull). Built test-first per the development workflow; 32 tests pass.
Each stub is replaced with a thin wrapper over libsodium-wrappers-sumo:
* init() awaits sodium.ready
* toBase64 / toBase64URL / fromBase64 use sodium's base64 variants;
fromBase64 tries all four (standard, standard-no-pad, URL-safe,
URL-safe-no-pad) so callers don't have to know which form Ente
delivered
* deriveKEK is sodium.crypto_pwhash with ALG_ARGON2ID13 and 32-byte
output
* deriveLoginSubkey is sodium.crypto_kdf_derive_from_key(32, 1,
'loginctx', kek).slice(0, 16) per the upstream Ente clients
* decryptBox is sodium.crypto_secretbox_open_easy
* decryptSealed is sodium.crypto_box_seal_open
* initStreamPull / pullStreamChunk wrap the secretstream pull API,
throwing on authentication failure rather than returning false
All 32 tests pass; make check is green.
Tests for the entire crypto/ public surface, written against the API
shape declared in the README. The accompanying src/crypto/ modules are
stubs that throw 'not implemented' so the test files compile and tests
fail with clear errors rather than module-not-found.
Tests cover:
* init() resolves and is idempotent
* fromBase64 / toBase64 / toBase64URL round-trips, including URL-safe
input with stripped padding (the form Ente uses for auth tokens)
* deriveKEK matches sodium.crypto_pwhash with Argon2id parameters
* deriveLoginSubkey matches sodium.crypto_kdf_derive_from_key with
subkey id 1 and ctx 'loginctx', truncated to 16 bytes
* decryptBox round-trips, rejects tampering, wrong key, wrong nonce
* decryptSealed round-trips, rejects wrong keypair and tampering
* Secretstream pull decrypts multi-chunk streams in order, exposes
per-chunk tags, rejects tampering, wrong key, and out-of-order chunks
* Constants STREAM_CHUNK_SIZE (4 MiB) and STREAM_CHUNK_OVERHEAD (17)
Tests are commented to serve as the canonical API documentation per the
README development workflow policy. Verified: 29 tests fail (red), 3
trivial constant tests pass; lint and fmt-check are green.
eslint.config.mjs is updated to honour the leading-underscore convention
for intentionally unused parameters (the stubs).
The 'sumo' build is required for crypto_pwhash (Argon2id), which Ente
uses to derive the KEK from the user's password. Pinned to exact
versions in package.json with integrity hashes in yarn.lock per repo
policy on hash-pinned external references.
Tests are deliberately excluded from the pre-commit hook so that the
TDD red-phase commit (failing tests landing before implementation) can
land on a feature branch. CI still runs full make check via docker build
so a red branch cannot reach main.
All changes go on a feature branch; the first commit on the branch is the
failing test suite for the change; the branch can only merge to main when
make check is green. Tests are the canonical API documentation and must be
commented thoroughly so a reader can learn the library from them.
Initial repo scaffolding per sneak/prompts NEW_REPO_CHECKLIST: WTFPL
LICENSE, REPO_POLICIES.md, editor and prettier dotfiles, JS toolchain
(TypeScript, ESLint, Prettier, Vitest with pinned versions), Makefile,
Dockerfile (node:22-alpine pinned by sha256), Gitea Actions workflow.
make check and make docker both pass.
Non-server image: brings up the dev environment and runs make check, per
repo policy on Dockerfiles for non-server repos. Base image hash matches
the sneak/prompts template (node 22-alpine, 2026-02-22).
Targets: test (vitest, with conditional verbose rerun pattern), lint
(eslint + prettier), fmt / fmt-check (prettier), check (test + lint +
fmt-check), build (tsc), dev (tsc --watch), clean, docker, hooks.
Uses GNU timeout when available to hard-cap make test at 30 seconds, per
repo policy. Falls through without a cap on systems where timeout is
absent.
package.json declares the project as ESM with NodeNext module resolution,
exposing dist/index.js as the library entry and dist/bin/quack.js as the
CLI binary. Dev dependencies are pinned to exact versions (yarn.lock holds
the integrity hashes per repo policy on hash-pinned external references).
Adds a placeholder src/index.ts and a single smoke test so make check is
not a no-op.
.gitignore extended for TypeScript/Node build artifacts on top of the
prompts-repo template. .editorconfig and .prettierrc match the prompts
template (4-space indents, prose-wrap always for markdown).
Reframes the project as the protocol foundation for a future Electron-based
Ente desktop client (the existing official clients are unsatisfactory).
Adds an API reference section with TypeScript declarations for every
exported name across crypto, auth, model, api, session, and Client modules.
Adds Phase 10 desktop-client TODO items so a future agent can pick up the
plan.