pithos/DESIGN-web-app.md
Local Dev 8742e104a2 Pithos: plan for the browser app on Drives on Silent Mode
Records why it must live on its own origin (every navigate.st/bns site
shares one origin and could read its keys), the two sign-in keys, the
AES-SIV port WebCrypto lacks, and the phases.
2026-10-05 02:06:47 +02:00

118 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pithos in the browser (plan)
Status: plan, 2026-10-05. Nothing built yet.
## Goal
Open your drives from any browser, on any device, with nothing installed:
browse, upload, download, rename, delete and share files on **Drives on
Silent Mode** (the hosted gateway at `https://s3.silentmode.st`).
Out of scope: a drive on your own computer (`http://127.0.0.1:8000`). s3d
sends no CORS headers, so a web page cannot talk to it; for that the website
hands over to the local Pithos ("Open my Pithos", port 47621).
## Where it lives: its own origin
**`https://s3.silentmode.st/app`**, served by the hosted gateway.
- Not on `navigate.st/bns/pithos.sia/app`: every BNS site served through
navigate.st shares the origin `navigate.st`, so any other `.sia`/`.bch` site
could open the app's window (same origin) and read the keys out of it, or
read anything it stored.
- Same origin as the API, so **no CORS** has to be opened on the gateway at
all, and the browser keeps the keys away from every other site.
- `pithos.sia/app` keeps its meaning: in Theseus it is the full app (the
add-on answers it); in any other browser the website's app-address hint
gets a third button, "Open in the browser app", linking to
`https://s3.silentmode.st/app`.
- Strict CSP (`default-src 'self'`, `connect-src 'self'`, no inline script,
`frame-ancestors 'none'`), no third-party scripts, files served by the
gateway from `Pithos/web/` (versioned with Pithos).
## Signing in
Two kinds of key, both loaded from a file (drag and drop or picker) or pasted:
1. **Your Pithos key** (owner, full access, encrypted drives readable).
- Without Theseus: the existing export, `pithos-hosted-key.json`
(`{v:1, secret}`), Accounts › On Silent Mode › Export key. From the secret:
identity seed = HKDF(secret, "", "pithos/hosted-identity/v1", 32),
encryption master = HKDF(secret, "", "pithos/hosted-encryption/v1", 32).
- With Theseus there is no file: the keys come from the vault. New export
**"Key for the browser app"** (vault unlocked + Theseus approval prompt):
`{v:2, identitySeed, encryptionKey}`, the two 32-byte values derived from
the vault paths `pithos/hosted-identity/v1` and
`pithos/hosted-encryption/v1`. NEVER change those paths. The file is as
powerful as the vault for these drives; the dialog says so.
- Flow: `GET /hosted/v1/challenge` → Ed25519 signature in WebCrypto
(PKCS8 wrapper `302e020100300506032b657004220420 || seed`) →
`POST /hosted/v1/session` → Bearer token → `GET /api/keys` → the account's
S3 key → S3 calls signed in the page.
2. **An S3 key file** (the Export JSON format `{endpoint, accessKey,
secretKey, bucket}`), including folder keys (grant keys `PG…`) from Share….
No encryption key: plain files and shared folders (stored readable) work,
encrypted names show as "encrypted file". The endpoint must be the
gateway.
Keys live **in memory only** by default; closing the tab signs out.
Optional "Remember on this device": the key file is wrapped with a
passphrase (PBKDF2-SHA256 600k + AES-GCM, as Save credentials… does) in
IndexedDB on the gateway origin. Sign out wipes it and calls
`DELETE` on the session.
## Crypto in the page
Port `core/crypt.js` and the signing part of `core/s3.js` to browser ESM
in `Pithos/web/lib/`, sharing test vectors with the Node versions.
- HKDF-SHA256, AES-256-GCM (bodies), AES-CTR, HMAC-SHA256 (SigV4): WebCrypto.
- AES-SIV (RFC 5297) for names is not in WebCrypto:
- CMAC/S2V from AES-CBC with a zero IV (WebCrypto appends a PKCS#7
block: take the block before it); one-block AES-ECB the same way.
- SIV-CTR with AES-CTR `counter = V'` (bits cleared as crypt.js does),
`length: 128`.
- No library: @noble/ciphers' `siv` is AES-GCM-SIV (RFC 8452), not RFC 5297.
- Tests: RFC 5297 vectors, plus Node-encrypts / browser-decrypts and back for
names (with the bucket + parent-path AD) and bodies (chunk sizes, ranges,
empty file), run under Node's WebCrypto in `npm test`.
## What the app does (v1)
- Drives list, folder browsing (merged encrypted + plain listing, as
`core/hosted.js` does), icons/list views.
- Upload: drag and drop; encrypted chunk by chunk (1 MiB) in the page;
multipart above ~64 MiB so big files never sit in memory whole.
- Download: decrypt as a stream (File System Access API where available,
else a Blob; very large files on browsers without it get a warning).
- Rename, move, delete, new folder (renames re-encrypt, as the desktop does).
- Share: public folder / link / folder key through `/hosted/v1/rules`.
- Viewer for pictures and text, audio/video player using range reads.
- Free space and account state (`/hosted/v1/me`, `/api/space`).
Later: the docked music player, offline cache, PWA install.
## Gateway changes (Pithos/hosted)
- Serve `GET /app`, `/app/*` (static files, strict CSP, long cache with
versioned names), before the S3/auth routing.
- Nothing else: same origin, so no CORS. The S3 path rules stay as they are
(owner keys raw-proxied to s3d; grant keys checked by `rules.js`).
- Rate limits already in place for sign-in apply.
## Phases
1. Crypto + SigV4 port with cross-tests (largest risk, done first).
2. Gateway `/app` route + sign-in with a key file + read-only browsing and
downloads.
3. Uploads, folders, rename/delete.
4. Sharing, viewer and player.
5. "Key for the browser app" export in Theseus; website button; docs.
## Open questions
- Is `s3.silentmode.st/app` the address, or a dedicated `pithos.silentmode.st`
(same design, another certificate and vhost)?
- Should the browser app also sign up new accounts (BNS signature / invite),
or only sign in to accounts made in Pithos?
- "Remember on this device": allow it, or always ask for the key file?