aboutsummaryrefslogtreecommitdiffstats
path: root/packaging
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-18 02:14:39 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-18 02:14:39 +0200
commit50ebb4f2e620dad8e1fbca8307b97c5e10e7e6c0 (patch)
tree0dd0d2f63ec70a4d459d12aff8f68d2f04881c70 /packaging
parentf23e8e51e4b8bc03d6109081fe048af1782e1f4e (diff)
downloadmeshbay-50ebb4f2e620dad8e1fbca8307b97c5e10e7e6c0.tar.gz
docs: settle the desktop client, and draft v6
A design discussion on 2026-08-17 settled Phase 13 and, in doing so, changed four things the spec states. v6 restates only those; v5 stays authoritative for everything it does not touch, per the convention v5 itself used with v4. What changed: * The native shell is **Electron**, not pywebview — structural decision 18 reversed. The SPA depends on Chromium-class APIs (WebRTC, WebCrypto X25519/Ed25519, MSE, Service Workers), so keeping Chromium keeps transport.js, crypto.js, keyderive.js, downloads.js and sw.js *as the client*. A system webview meant reimplementing ~2500-3000 lines. The old "69 % reused" figure was measured against an app.js of ~2600 lines; it is 4586. * A group's content is **several named roots**, not one directory, because the planned video and audio libraries will not live in one folder on one disk. * **Device linking**: one person may hold several devices on a node, admitted by a key the node already pinned and bound by a one-time code the new device generates. Without it a native client is refused where a browser is not, and an account created natively could never be opened in a browser. * **Authorship is authenticated, not asserted** — chat senders sign, uploads have a provable owner, and delete authorization moves from the uploading key to the account. And one rule v5 assumed without writing down: **group-related server state lives on the node.** Verified for multi-root — SwarmSource carries hashes and endpoints, no paths. Also here: the Caddy configuration, which was a snippet in the roadmap that would have broken the SPA (it predates /a/<hash>/ asset versioning and would have 404ed /sw.js, silently killing streamed downloads on Firefox and Safari); and downloads.html, which becomes a security page once a release key exists. Phase 15 was re-read against device linking and is wrong as written: a sender key must be per **device**, never per person, or two devices sharing a chain produce key and nonce reuse — C1 again, one level down. senderkeys.py already fails this silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packaging')
-rw-r--r--packaging/caddy/meshbay.org.Caddyfile64
1 files changed, 64 insertions, 0 deletions
diff --git a/packaging/caddy/meshbay.org.Caddyfile b/packaging/caddy/meshbay.org.Caddyfile
new file mode 100644
index 0000000..c161202
--- /dev/null
+++ b/packaging/caddy/meshbay.org.Caddyfile
@@ -0,0 +1,64 @@
+# Caddy configuration for meshbay.org
+#
+# Two things share one origin: the public site (`site/`, static, meshbay.org
+# specific) and the hub (FastAPI on loopback:8000, generic and reusable).
+#
+# The rule is an ALLOWLIST for the site, and everything else to the hub.
+# Not the reverse. The hub mounts its whole static directory at "/"
+# (`app.py`, RevalidatingStatics), so a `root * site` with `try_files` would
+# shadow it and break the application in ways that are not obvious:
+#
+# /sw.js the service worker MUST stay at the root or its scope stops
+# covering the pages it intercepts downloads for. A 404 here
+# silently breaks streamed downloads on Firefox and Safari.
+# /a/<hash>/* the versioned module graph. The old snippet in
+# devel-phases-next.md proxied `/style.css` and `/*.js`, which
+# matches neither this prefix nor /locales/*.js — it predates
+# asset versioning and would 404 the entire bundle.
+# /style.css old bookmarks, still served unversioned by the hub.
+#
+# Deployment: the site is NOT pushed by the hub deploy procedure. Sync it
+# separately to /srv/meshbay/site (see QE/server-state/meshbay.org.md).
+
+meshbay.org {
+ encode zstd gzip
+
+ root * /srv/meshbay/site
+
+ # The public site. Extensionless URLs work: /about → about.html.
+ # Keep this list explicit — anything not named here belongs to the hub.
+ @site path / /about /about.html /downloads /downloads.html /assets/*
+ handle @site {
+ # These pages are pure HTML and CSS: no script, no external asset, no
+ # form. The policy says exactly that, so an injection has nowhere to go.
+ header {
+ Content-Security-Policy "default-src 'none'; style-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'"
+ X-Content-Type-Options "nosniff"
+ Referrer-Policy "same-origin"
+ # Deliberate: this host is HTTPS only. Removing it later takes
+ # max-age to expire in every browser that saw it.
+ Strict-Transport-Security "max-age=31536000; includeSubDomains"
+ }
+ try_files {path} {path}.html
+ file_server
+ }
+
+ # Everything else is the hub: /v1/*, /app, /app/*, /a/<hash>/*, /sw.js,
+ # /style.css, /locales/*, /vendor/*, and the /v1/nodes/ws WebSocket
+ # (reverse_proxy upgrades it without extra configuration).
+ #
+ # The hub sets its own CSP for the application, which needs
+ # `wasm-unsafe-eval` for the Argon2id bundle KDF. Do not add a header here:
+ # a second policy on the same response is intersected with the first, and
+ # the strictest wins — which would lock every user out of their keys.
+ handle {
+ reverse_proxy 127.0.0.1:8000 {
+ # The hub honours X-Forwarded-For from a trusted proxy only, and
+ # reads the rightmost hop (draft-v5 §6.4). Caddy's default is to
+ # APPEND the real address to whatever the client sent, which the
+ # rightmost-hop rule already handles; this replaces it outright so
+ # nothing a client invents ever reaches the compliance log.
+ header_up X-Forwarded-For {remote_host}
+ }
+ }
+}