From 68bfe56a19aeb4c16f8e185fc85d8eee61aef78f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Tue, 18 Aug 2026 10:30:59 +0200 Subject: fix(client): the desktop client runs, and running it corrected three things MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Electron 42 / Chromium 148, launched under xvfb. The packaged interface mounts over `app://` with a secure context, `crypto.subtle` present, Argon2 WASM loaded, and no console errors. Three statements in the design were wrong, and only launching it found them. **A CSP in a `` tag silently drops `frame-ancestors`.** Chromium says so in the console. A policy carrying a directive that does nothing is worse than one without it, so the policy is sent as a header by the protocol handler — which is also the only thing serving the interface, so one source instead of two. **`secure: true` is not what makes the service worker register.** Chromium refuses a worker on a custom scheme whatever its privileges: "The URL protocol of the current origin ('app://meshbay') is not supported". The application has no service worker and needs none — it saves through a native dialog, which is the better of the two paths. `sw.js` stays in the package because the same files serve the browser, where it is one of only three ways to write a large file. What `secure: true` is actually for was measured at the same time: without it **the whole of `crypto.subtle` is undefined**. The first probe loaded a `data:` URL and every algorithm failed with TypeError, AES-GCM included — which is why the probe was rewritten before believing its answer. X25519 and Ed25519 are both present on Chromium 148, settling the version floor left open as O6. **The renderer cannot call the hub.** Its origin is `app://meshbay` and CORS refuses it. The hub has *no CORS middleware at all* — its API is reachable from no web origin whatever — and that is worth keeping. Widening it for `app://meshbay` would be worse than it looks: that origin is not a credential, since any Electron application can claim the same scheme and host name. So every hub call leaves from the main process, exactly as saving a file does, and it refuses any origin that is not the hub the user signed in to. `platform.apiFetch()` is `fetch` in a browser and the bridge in the application, so no caller has to know which it got. `transport.js` reaches it through a global because it is a classic script, not a module — the alternative was a second fetch path, which is how two callers of one hub start disagreeing about how to reach it. Verified from inside Electron: the main process gets 200 from /v1/hub/version, the renderer is refused by CORS, and **a script served by the hub is refused by the policy** — T3's mitigation demonstrated rather than asserted. Build note, written into the README because it will bite the next person: **Ubuntu 24.04's nodejs 18 cannot install Electron at all** — the download script `require()`s an ESM module, which Node gained in 22. Node 24 LTS, checksum-verified against nodejs.org, is what this was built with. package-lock.json is committed; builds use `npm ci`, not `npm install`. 799 tests pass, e2e.py still passes end to end. The session harness needed a platform stub: it lifts `hubFetch` out of app.js as text and runs it, so the adapter is now part of the environment it models. Co-Authored-By: Claude Opus 5 --- packages/meshbay-client/README.md | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 packages/meshbay-client/README.md (limited to 'packages/meshbay-client/README.md') diff --git a/packages/meshbay-client/README.md b/packages/meshbay-client/README.md new file mode 100644 index 0000000..46be72b --- /dev/null +++ b/packages/meshbay-client/README.md @@ -0,0 +1,43 @@ +# MeshBay desktop client + +The interface ships **inside this package** and loads from disk. A shell that +points a WebView at the hub's `/app/` is a browser with a different icon and +fixes nothing — that is finding T3, and removing it is the reason this exists. + +## Building + +Needs **Node ≥ 22**. Ubuntu 24.04 ships nodejs 18, which cannot install Electron +at all: the download script `require()`s an ESM module, which Node gained only in +22. Fedora 44 is fine. + + # once, on a machine whose distro is too old: + curl -fsSLO https://nodejs.org/dist/v24.19.0/node-v24.19.0-linux-x64.tar.xz + curl -fsSLO https://nodejs.org/dist/v24.19.0/SHASUMS256.txt + grep " node-v24.19.0-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c - + sudo tar -xJf node-v24.19.0-linux-x64.tar.xz -C /opt/nodejs --strip-components=1 + export PATH=/opt/nodejs/bin:$PATH + + npm ci # not `npm install` — the lockfile is the build input + npm run sync-ui # copy the interface from the hub package + npm start + +`ui/` is generated and is not committed. The interface has exactly one source, +`packages/meshbay-hub/src/meshbay_hub/static/`, and a silent fork is the only +real way to end up maintaining it twice. + +## Running headless + + xvfb-run -a ./node_modules/electron/dist/electron --no-sandbox . + +## What it does not have + +**No service worker.** Chromium refuses to register one on a custom scheme, so +the streamed-download path never runs here — the application saves through a +native dialog instead, which is the better of the two. `sw.js` is still shipped +because the same files serve the browser, where it is one of only three ways to +write a large file. + +**No direct network from the renderer.** Its origin is `app://meshbay`, which +CORS refuses, and the hub has no CORS middleware at all — a posture worth +keeping. Every hub call leaves from the main process, which refuses any origin +that is not the hub the user signed in to. -- cgit v1.2.3