| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Stage 4 of ~/next/improve-downloads.md, the flag day. Leases become compulsory
and a 2.x peer is refused at the handshake.
**The bound on leaseless reads (§3.4.1) did not exist, and it is what makes the
rest mean anything.** Browsing a group is never subject to a transfer slot —
that is an operator decision and a requirement: a member must be able to browse
a group at capacity exactly as they browse an idle one. But "not leased" cannot
mean "unbounded", or a client that simply omits `tr` transfers outside every cap
and the caps are decoration. A session may now read two distinct files at once
without a lease: one because a viewer looks at one file, two so that prefetching
the next photo stays possible. A count of files and not a byte budget, because a
RAW photo is 60-80 MB and is browsing while a 40 MB archive is a download, and
no size threshold separates them. Thumbnails, posters and cover art never reach
this check at all — they resolve out of the node's own cache.
It is a fairness control among cooperating clients, in the company of
`max_concurrent_streams`, and is not a defence against a member determined to
saturate a node's disk. That member is a member, and the answer to them is
`member revoke`.
**MNP_VERSION and MNP_MIN_SUPPORTED both move to 3.0**, on both sides. The
messages are additive; the requirement is not. An opt-in switch would leave a
leaseless branch reachable on every node, which is finding C6's lesson — a
transport that accepted a bare JWT — one feature later.
**The desktop client now checks before it connects.** The SPA is served by the
hub and picks up a new client on reload; the application ships its own
interface, so an un-updated one would sign in, list groups, and fail every
connection with `version_too_old` — a refusal in a protocol vocabulary with
nothing anyone can act on. It asks `/v1/hub/version` for `client.minimum` and
says so plainly instead. An unreachable hub is deliberately *not* "too old": a
captive portal or a closed laptop must not make starting the application
impossible.
**Every package is aligned on 0.13.0.** `meshbay-client/package.json` had
drifted to 1.0.0 while the Python packages were on 0.12.0 — invisible until
something compared those numbers, and then load-bearing: an installed client
announcing 1.0.0 sorts above a 0.13.0 minimum and walks through the gate meant
to stop it. That is stated in the code rather than left to be rediscovered; it
is acceptable exactly once, because the operator is updating every client, node
and hub by hand for this flag day. A new test fails if two packages ever
disagree again, and another fails if the hub would refuse the client the tree
builds.
Node suite 1209 passed, hub suite 861 passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
winget install ffmpeg was considered and rejected as the mechanism: it
needs network access and winget/App Installer present at the exact
moment setup runs, and its failure mode is silent -- video just does
not stream, with nothing pointing back at ffmpeg. Not viable for a
non-technical install.
MeshBay transcodes browser-incompatible video to H.264 (-c:v libx264,
webrtc_server.py) -- a real encode, not remux -- so this needs a genuine
GPL ffmpeg build; no LGPL-only build includes an H.264 encoder, since
libx264 itself is GPL.
packaging/win/fetch-ffmpeg.ps1 (new)
Downloads, checksum-verifies and stages ffmpeg for the build. Source:
BtbN/FFmpeg-Builds' Windows x86_64 gpl-shared preset -- shared DLLs
rather than two independent static binaries, which is what nearly
tripled this: the "full" static build many devs already have via
winget is ~220 MB *per executable*. Pinned to one dated release tag
(immutable once published) and its own sha256, not the "latest" alias
BtbN repoints on every auto-build -- verified by hand first (downloaded,
hash matched, ran a real encode+probe with libx264) before pinning.
ffplay.exe (an SDL2 player, ~17 MB) is dropped; MeshBay never invokes
it. Cached after the first build. Runs its own smoke test (encode +
probe a real clip) so a broken fetch fails at build time, not for the
first user who tries to watch something.
packaging/win/LICENSE-ffmpeg.txt (new)
GPLv3 notice + where the corresponding source is, required because
this redistributes a GPL binary even though it is unmodified and only
ever invoked as a subprocess. Ships alongside ffmpeg.exe in the
installer.
build-node-runtime.ps1 / build-win.ps1
Bundling is now the DEFAULT, replacing the old opt-in -FfmpegDir (which
copied from a local directory and left most builds without ffmpeg at
all). -SkipFfmpeg opts out for a smaller, streaming-less local-iteration
build.
Also fixes a real bug the ffmpeg change exposed rather than caused: the
final `--help` smoke test did `$help -notmatch "meshbay-node"` against
$help captured as a PowerShell ARRAY (one element per line) -- -notmatch
on a collection is a FILTER, not a boolean test, and returns the
non-matching elements; any non-empty array is truthy in if() regardless
of content. Once --help wrapped past one line (it now does, with
autostart/service in the verb list) this threw unconditionally. Fixed
by joining to one string before matching, and pinned by a new test so
a future edit cannot silently reintroduce the collection-vs-scalar trap.
Verified: downloaded and hashed the pinned release by hand (matches),
ran a real libx264 encode + ffprobe against the extracted build,
fetch-ffmpeg.ps1 end to end (161 MB staged), a full build-node-runtime.ps1
run (308 MB node-runtime/) and a full installer build (MeshBay-Setup-
1.0.0.exe, 210.8 MB with ffmpeg bundled). Node suite 850 pass / 25 skip.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The per-user Startup-folder launcher (W3) only ever runs after this user
signs in. A real Windows Service would start earlier, but under
LocalSystem/NetworkService -- accounts with no normal profile, so
%LOCALAPPDATA%\meshbay\ (config, keystore, data) would not exist for it.
Relocating storage to make that work is real surgery, deliberately not
done here.
Instead: a Scheduled Task, created once with admin rights, that runs AS
THIS USER at boot without needing them to sign in first.
`schtasks /create ... /ru <user> /rp ""` with no `/it` registers an S4U
(Service For User) logon -- no password stored anywhere, and unlike
LocalSystem it loads this account's own profile, so config_dir()/
data_dir() need zero changes. The cost: S4U carries no network credential,
which the node never needed -- everything it touches is local disk plus
outbound internet. Creating the task needs admin (a boot trigger touches
system-wide scheduler state, the same reason /sc onlogon needed it);
querying/starting/stopping an existing one does not -- Task Scheduler
grants the owning user that much itself, which is what lets the Node
page's Start/Stop/Restart drive it with no further UAC prompts.
meshbay_node/platform.py
service_install/_remove/_status/_run/_end -- mirrors autostart_* but
for the Scheduled Task; TASK_NAME moved here (was decorative before)
meshbay_node/daemon.py
new `service install|remove|start|stop|status` verb; restart-daemon and
reset now check for the service task too
packaging/win/service.ps1
the installer-side equivalent (extraResource); status/run/end never
self-elevate -- only install/remove do, exactly matching what
Task Scheduler itself requires
packaging/win/service-mode.ps1
ONE elevated helper running service.ps1 + firewall.ps1 together, so
choosing service mode costs exactly one UAC prompt, not two
build/installer.nsh
the install-time choice: "run as a background service?" (one
elevation, both jobs) vs the existing per-user + separate firewall
question. Checked first, unelevated, so re-running setup with
everything already configured asks nothing. Uninstall offers the
matching one-elevation cleanup, default No.
src/main.js
winServiceTaskStatus/Run/End, wired into node:installed,
node:service-status/-stop/-restart and node:start: when the Scheduled
Task exists, drive it; otherwise fall back to the existing per-user
spawn/kill path. This is the hard requirement -- Start/Stop/Restart
from the Node page must work in either mode.
node-page.js / locales
a hint explaining why the per-user autostart toggle is absent when
service mode is active (info.mode from the backend, no new field to
gate on -- it just isn't sent in that case)
package.json: 0.1.0 -> 1.0.0.
Verified: electron-builder compiles the new NSIS choice logic and ships
all three scripts; service.ps1's S4U install fails cleanly (Access
denied) when run unelevated, and its status/run/end never touch "runas".
Cannot verify the elevated success path myself (no admin in this
session) -- that needs a real UAC click. Node suite 843 pass / 25 skip;
test_packaging_win.py pins the one-elevation property, the S4U flags,
and that main.js actually checks the service task in all three handlers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Installing used to mean clicking through two separate Windows "Allow
access" prompts later — one for MeshBay.exe, one for meshbay-node.exe —
each confusing on its own and worse before the exe carried a version
resource. Adding a firewall rule needs admin, and the installer is
deliberately per-user with no elevation, so this can only ever be opt-in.
packaging/win/firewall.ps1 (new, shipped as an extraResource at
resources\firewall.ps1): idempotent add/remove of the two inbound UDP
rules ("MeshBay", "MeshBay Node"), grouped, logged to
%TEMP%\meshbay-firewall.log. Locates both executables from its own path,
no arguments needed beyond the action.
build/installer.nsh: customInstall asks "Allow MeshBay through Windows
Firewall now?" and runs firewall.ps1 via NSIS ExecShellWait "runas" — one
UAC prompt — only when not ${Silent}; declining or dismissing UAC falls
back to Windows' own per-process prompts, unchanged. customUnInstall
offers the same in reverse, defaulted to No (a stale rule for a deleted
exe is inert, so this should not nag on the way out) and skipped for a
silent uninstall.
Verified: rebuilt MeshBay-Setup-0.1.0.exe (electron-builder compiles the
new LogicLib.nsh / ExecShellWait NSIS successfully); firewall.ps1 run
unelevated fails cleanly into its log ("Access is denied") rather than
silently doing nothing, confirming the fallback path. Node suite 835
pass / 25 skip.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`npm run dist:win` produces MeshBay-Setup-<version>.exe: the Electron client
and, beside it under resources/node-runtime/, the frozen meshbay-node daemon
(meshbay-common inside it). No hub. Per-user, no elevation — matches the W3
constraint that a logon-triggered scheduled task needs admin.
electron-builder / package.json
build.win nsis, build/icon.ico, extraResources -> node-runtime/
build.nsis oneClick:false perMachine:false allowElevation:false
allowToChangeInstallationDirectory:true
dist:win -> packaging/win/build-win.ps1 (mirrors dist -> build-client.sh)
packaging/win/
meshbay-node.spec + node-entry.py PyInstaller freeze of
meshbay_node.daemon:main. The awkward deps (aiortc, av, aioquic,
pydantic_core, uvicorn, watchdog, guessit, blake3, tzdata) are pulled
in whole with collect_all — that list is expected to grow when a frozen
run raises ModuleNotFoundError.
build-node-runtime.ps1 throwaway venv -> pip install -> PyInstaller ->
packages/meshbay-client/node-runtime/ (gitignored)
build-win.ps1 Node>=22 check, npm ci, Electron bump, sync-ui,
node runtime, electron-builder --win nsis
bump-electron.mjs the Chromium-CVE "build against latest Electron"
policy, out of the PS script (5.1 here-string terminator rules)
README.md
PyInstaller, not the python-embed zip: the frozen meshbay-node.exe is a
genuine relocatable single binary, which is what src/main.js:findNodeBinary
spawns (process.resourcesPath/node-runtime/meshbay-node.exe when packaged) and
what the W3 autostart launcher points at. The embeddable zip needs pip to make
that wrapper and the wrapper bakes in an absolute interpreter path.
build/installer.nsh: on uninstall, taskkill meshbay-node.exe and delete the W3
Startup .vbs (it would point wscript at a deleted binary every sign-in).
%LOCALAPPDATA%\meshbay\ — node.toml, keystore.enc — is never touched.
ffmpeg is not bundled by default (node finds it on PATH); build-win.ps1
-FfmpegDir copies ffmpeg.exe/ffprobe.exe in for a self-contained installer.
Verified on the Windows guest: PyInstaller freeze builds first try
(node-runtime 147 MB), frozen `meshbay-node status` talks to the live daemon's
loopback API; electron-builder --win nsis produces MeshBay-Setup-0.1.0.exe
(155 MB), oneClick/perMachine flags applied, node-runtime bundled at the path
findNodeBinary expects. test_packaging_win.py (14) pins the config invariants
and the NSIS <-> platform.py autostart seam. Node suite 798 pass / 34 skip.
Open: Authenticode signing (13.9 — unsigned => SmartScreen), Windows CI
(18.3), electron-updater. First clean-machine install + DPAPI + autostart
round-trip is a manual check.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
package twice
Chromium CVEs are fixed in Electron releases, and a client built against
an old one ships those holes to every user. That is a certain harm; a
build that breaks on a new Electron is a repairable one. build-client.sh
now bumps to the latest on every build, prints the comparison, and lets
the build fail if it cannot cope — the failure is the signal to fix, not
a reason to stay behind. It writes package.json and the lockfile on
purpose: the new pin is meant to be committed. A registry it cannot reach
is a warning, not a failure.
Exercised by pinning back to 42.9.2 and building: "==> Electron 42.9.2 ->
44.1.1", exit 0, electron=44.1.1 in the packaged output. Note npm audit
would have said nothing about any of this — Chromium CVEs fixed in
Electron do not reliably reach the npm advisory database.
Separately, package.json declared linux.target [deb, rpm] with its own
deb/rpm depends, so `npm run dist` built a second package under the same
name. The two had drifted: /opt/MeshBay/meshbay-client against
/opt/meshbay-client/meshbay, and Depends: python3-meshbay-common naming
none of the Electron runtime libraries the real DEBIAN/control lists — it
would have installed cleanly and then refused to start. Nothing in the
tree referenced `npm run dist`, which is why the drift was free to
happen. That config is gone, "dist" delegates to build-client.sh, and
test_desktop_shell.py refuses its return.
`--dir` was re-run with no linux block at all: exit 0, same binary
build-client.sh consumes. It needs appId, productName and files, nothing
else.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbwJDbNTkiRUh7HTWEoyss
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
electron-builder warned `author is missed in the package.json` on every
build, including the `--dir` one build-client.sh runs, and refused the
deb/rpm targets outright over it and over a missing homepage. Both were
pre-existing — builder 25 emitted the identical warning — and had simply
never been hit, because those targets had never been built.
The values are copied verbatim from packaging/deb/meshbay-client/DEBIAN/
control, which already declared them, so the two cannot disagree.
Not added: `desktopName`, despite the warning that asks for it. The path
this project actually ships (build-client.sh + packaging/desktop/
meshbay.desktop) already sets StartupWMClass=MeshBay, and src/main.js
sets --class to match for dev runs. The warning concerns the .desktop
electron-builder generates for its own deb/rpm targets, which is not what
gets installed.
That is the larger thing found here and left open: `npm run dist` defines
a second, incompatible layout for a package of the same name —
/opt/MeshBay/meshbay-client against /opt/meshbay-client/meshbay. See
~/next/npm-audit.md §9.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbwJDbNTkiRUh7HTWEoyss
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
npm audit reported 12 findings (11 high, 1 critical), every one transitive
and every one reached through electron-builder. The critical was tar
(<=7.5.20), a family of path-traversal and symlink-poisoning advisories.
electron-builder is a devDependency and build.files is src/** and ui/**,
so none of it ships: the exposure was to whoever builds a release, not to
users. Real, since a build machine producing signed artefacts is worth
attacking, but it should not have been read as "the client has a critical
vulnerability".
electron-builder ^26.15.3 takes the audit to 0 on its own. It is a major,
so it was measured rather than assumed: a --dir Linux build passed before
and after, and the config used here (appId, files, linux.target,
deb/rpm.depends) is nowhere near where 26's breaking changes are. The
produced app.asar is not byte-identical to 25's, which matters only for
18.7's hash-and-compare story and is a release note, not a defect.
electron ^42.11.1 is a patch bump inside the range already declared, where
Electron ships its security backports. The built binary was launched under
xvfb: two processes alive after 25s, empty log. That is the part that
counts — test_desktop_shell.py pins the security contract by reading
source, so it would stay green through any runtime regression.
protobufjs's override floor goes ^7.5.5 -> ^7.6.5. The override itself is
load-bearing and must stay: removing it drops castv2-client's protobufjs
to 6.11.6, which carries a critical RCE advisory — and unlike everything
above, protobufjs ships inside the application. But ^7.5.5 permitted 7.5.5,
which is inside a high advisory's range (<=7.6.4); npm happened to resolve
7.6.6, so the protection was incidental rather than structural.
Electron 44 is deliberately not taken here: two majors and a different
Chromium, and nothing in the suite would notice a regression. It needs its
own launch session.
Audit and evidence: ~/next/npm-audit.md (not in the repo).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbwJDbNTkiRUh7HTWEoyss
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Shared venv architecture: meshbay-common owns the Python venv with all
pip deps pre-installed; hub and node add only their code into it.
Client is a standalone Electron app. No pip runs at install time.
- Add build scripts (packaging/build/) for common, hub, node, client
- Add orchestrator build-packages.sh with deb/rpm auto-detection
- Add .deb control/postinst for all 4 packages
- Add .rpm specs for all 4 packages (replaces python3-meshbay-common)
- Add Gnome .desktop launcher and icon resizing
- Add firewalld services (meshbay-cast, meshbay-node) and UFW profiles
- Update systemd units to use /opt/meshbay-common/venv/bin/ paths
- TMDB token baked into node package at build time via QE/node.env
- Fix package-lock.json sync for protobufjs override
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
The root .gitignore ignores build/ (Python convention), which silently
prevented sync-ui.js and its companion index.html from being committed.
Rename to scripts/ so the files are tracked normally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Re-serve decrypted fMP4 video over HTTP on the LAN so a Chromecast can
play the stream. The relay runs in the Electron main process — same trust
boundary as downloads and MSE playback.
- cast-relay.js: HTTP server with BoxAccumulator (reassembles WebRTC
chunks into moof+mdat pairs), ring buffer, backpressure, finish() for
clean end-of-stream, fixed port range 19550-19553
- cast-chromecast.js: mDNS discovery (bonjour-service) + CASTV2 protocol
(castv2-client), connect/reload/disconnect lifecycle
- Seek-aware: relay restarts on every seek, Chromecast reloads new URL;
generation counter prevents stale async errors from killing active
restarts; landingPlayheadRef suppresses programmatic seeking events
- Device picker in video top bar with scan, device selection, copy-URL
fallback, and cast status indicator
- IPC bridge (main/preload/platform) for start/push/stop/finish/status/
discover/chromecastConnect/chromecastReload/chromecastDisconnect
- Phase 3 design doc for DLNA/Smart TV in docs/cast-smart-tv.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 `<meta>` 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 <noreply@anthropic.com>
|
|
|
Stage D, and the honest half of it.
D1 — the seam (done, and verified)
----------------------------------
`static/platform.js`. `HUB` becomes `platform.hubBase()` and the transport is
built with the same base, so one address has one source. In a browser it returns
'' and every path stays relative to the origin that served the page — the
acceptance criterion for this split was "the browser SPA behaves identically",
and it does. `platform.js` joins `_ASSETS`, or a change to it would not move the
content hash and a cached browser would never ask for it.
D2 — the shell (written, never launched)
-----------------------------------------
**There is no npm on this machine. Electron was never installed and
`packages/meshbay-client/` has not been run once.** That is stated here rather
than discovered later.
What is there: a main process serving the packaged interface over a privileged
`app://` scheme (`secure` and `standard` are not cosmetic — without them the
service worker refuses to register and streamed downloads break silently), a
preload exposing an enumerated bridge that never passes a filesystem path, a
window with `sandbox`, `contextIsolation` and no node integration, navigation
away from the package refused, and a CSP where the hub is reachable over
connect-src and is not a script source. The hub address arrives as a process
argument because `platform.hubBase()` runs before anything can await.
`test_desktop_shell.py` pins each of those by reading the source — the treatment
`test_downloads.py` already gives the three browser save paths. It catches a
property being removed and proves nothing about the application running. Two
were checked by breaking them.
The interface is *copied* into the package by `build/sync-ui.js` from the hub's
static directory, and `ui/` is gitignored: a silent fork is the only real way to
end up maintaining the interface twice.
D3 — partial
------------
The bridge, and the part worth having now: safeStorage's backend is reported
rather than assumed. On Linux it falls back to a fixed key when no keyring is
running, silently — someone who believes the OS is holding their keys is told
when it is not. The native key lifecycle belongs with D4 and needs a running
application to mean anything.
D8 — partial, and a real defect found
--------------------------------------
`meshbay-node.spec` installed the SYSTEM template — the one carrying `User=%i` —
into `%{_userunitdir}`. A user unit already runs as its owner and cannot carry
`User=`; systemd refuses the file, so the packaged unit could never have
started. Nothing noticed because nobody had built and installed the RPM.
Two units now: the template to `%{_unitdir}`, and a new `meshbay-node-user.service`
that a person enables themselves without a password — which is what lets the
desktop client install a node without asking for one. It carries ExecReload, so
`meshbay-node reload` does not have to stop a service somebody is streaming from,
and documents the drop-in for a drive outside the home, RequiresMountsFor
included.
798 tests pass; e2e.py still passes end to end. Nothing here was built or
launched: no npm, no rpmbuild.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|