pithos/hosted/README.md
Local Dev 9727ce79d3 Pithos: document hosting on Silent Mode and the gateway
Records what was built against the plan (names are encrypted from v1, rights
for other people are folder-scoped S3 keys), how to run pithos-hosted, and
that paid storage belongs to Hestia, a separate product.
2026-10-04 01:44:23 +02:00

73 lines
3.3 KiB
Markdown

# pithos-hosted
The server half of Pithos's *On Silent Mode*: one s3d per person, each on
that person's own Sia account, behind a gateway that adds sign-in, per-folder
access and traffic limits. The client half (encryption, moving drives) is in
`../core/hosted.js` and `../core/hosted-routes.js`.
## What it serves
| Path | Who | What |
| --- | --- | --- |
| `/hosted/v1/challenge`, `/hosted/v1/session` | anyone | Ed25519 sign-in; first sign-in needs a sign-up proof |
| `/hosted/v1/me`, `/rules`, `/data/...` | session | account, access rules, moving the s3d data folder in and out |
| `/api/...` | session | the owner's Pithos API, forwarded to their s3d's control server (an allowlist; object routes are refused so nothing bypasses client-side encryption) |
| `/p/<account>/<drive>/<path>` | anyone | files under a public rule |
| `/l/<token>` | anyone | one file under a share link, until it expires |
| everything else | S3 keys | path-style S3. Owner keys go straight to their s3d, which checks the signature; keys minted for other people are verified here, held to their folder and rights, and re-signed with the owner's key |
s3d processes listen on loopback only (`portBase + 2 * slot`). Each one
starts on the account's first request and is stopped after `idleMinutes`,
leftovers flushed to Sia first; at most `maxRunning` run at once.
State is files under `root`: `users/<id>/` (account, s3d.yml, data, rules,
usage), `sessions.json` (token hashes), `gate.json`, `keys.json`,
`grants.json`, `links.json`. Back up that folder and you have backed up the
service.
## Sign-up gate
`gate` in the config enables any of:
- `bns: { api }`: the user signs `pithos-hosted signup <account id>` with
the wallet that owns a BNS name; `api` is a BNS gateway answering
`/api/name/<name>` with the owner. One slot per name.
- `deposit: { address, minSats, confirmations, electrum: { host, port, tls } }`:
a BCH payment to `address` carrying OP_RETURN `pithos:<account id>`. One
slot per transaction. Refunds are an operator decision.
- `invites: ["code", ...]`: one use each.
`perIpPerDay` limits sign-ups per client address (set `trustProxy` behind
nginx so `X-Forwarded-For` is used).
## Running it
```bash
cd /opt/pithos && npm install --omit=dev --omit=optional
cd hosted && npm install --omit=dev
cp deploy/pithos-hosted.example.json /etc/pithos-hosted.json # edit it
node main.js --config /etc/pithos-hosted.json
```
`deploy/` has a systemd unit and an nginx site for `s3.silentmode.st`
(streamed bodies, `Host` passed through: s3d checks signatures against the
host the client signed). The s3d binary must be the version Pithos pins
(`core/binary.js`), the same on both sides of a move.
Stopping the service flushes every running s3d first, so give systemd time
(`TimeoutStopSec=300`).
## Tests
`npm test` here covers SigV4 verification, rules and the sign-up gate.
The full path (move up, encrypt, share, grant, move back) needs a real s3d;
it was exercised against a mock indexer during development.
## Not yet
- Signed streaming uploads (`STREAMING-AWS4-HMAC-SHA256-PAYLOAD`) from shared
keys are refused; owner keys are unaffected.
- Shared keys and links reach readable copies only. Sharing encrypted files
with a person (wrapping the folder key to theirs) is the next step.
- No quotas here: storage is each person's own Sia account. Paid storage is
Hestia, a separate product.