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.
This commit is contained in:
parent
251f95cdee
commit
8742e104a2
1 changed files with 118 additions and 0 deletions
118
DESIGN-web-app.md
Normal file
118
DESIGN-web-app.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# 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?
|
||||
Loading…
Add table
Reference in a new issue