summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-client/build/installer.nsh
Commit message (Collapse)AuthorAgeFilesLines
* feat(packaging): one radio page for Windows autostart, firewall every mode0.13Christophe Besson2026-09-111-43/+131
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Operator feedback on the 0.13.0 installer: - The all-users / current-user page (electron-builder's PAGE_INSTALL_MODE) only ever showed "anyone who uses this computer" disabled -- MeshBay is per-user only (account-bound keystore/DPAPI, MESHBAY_DESIGN.md 11.2) and build.nsis forbids elevation. customInstallMode forces $isForceCurrentInstall so the page is skipped. - The two nested Yes/No MessageBoxes are one nsDialogs radio page (customPageAfterChangeDir): only-while-open / at-sign-in / background service, default background service. customInit seeds MB_AutoMode "2" for silent installs where the page never runs. "At sign-in" now writes the Startup .vbs from the installer (meshbay-node autostart install, unelevated); the old per-user branch set up nothing. - The firewall rules go in for every mode, not behind a second opt-in -- a node that accepts no connections is the failure mode MESHBAY_DESIGN.md 7.5 names. Folded into the service elevation for mode 2; their own single elevation for 0/1. Unelevated short-circuit kept but narrower: firewall.ps1 check AND service.ps1 status must both pass to skip mode 2's UAC. Var MB_AutoMode lives inside customPageAfterChangeDir, not at file scope: the uninstaller compile pass inserts none of the macros that read it and makensis -WX turns "unused Var" (6001) into a hard error. Not yet exercised on a real machine -- the NSIS UI cannot be driven from the build env. test_packaging_win.py pins the script shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: opt-in Windows service mode (boot-time, one elevation) + v1.0.0Christophe Besson2026-09-041-31/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* fix(packaging): re-running setup no longer re-prompts for firewall accessChristophe Besson2026-09-041-13/+21
| | | | | | | | | | | | | | | | | | | Every run of customInstall showed the "Allow MeshBay through Windows Firewall?" question and, on Yes, a fresh UAC prompt -- an upgrade or repair install would ask again even with all four rules already in place. customInstall now checks first: firewall.ps1 check, unelevated (Get-NetFirewallRule needs no admin, only New/Remove do), exits 0 if every rule already exists. Only a nonzero result reaches the MessageBox and the elevated add. A second run of setup on an already-configured machine now asks nothing. Verified unelevated: check exits 1 and logs which rules are missing on a machine with none of them (the fresh-install case); electron-builder compiles the nsExec::Exec / Pop $0 / ${If} wiring. Node suite 837 pass / 25 skip. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat(packaging): offer one elevated firewall step instead of two dialogsChristophe Besson2026-09-041-4/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* feat(packaging): put the bundled meshbay-node on the per-user PATHChristophe Besson2026-09-041-5/+33
| | | | | | | | | | | | | | | | The installer had no console entry point, so running the CLI meant cd-ing into resources\node-runtime\ every time. installer.nsh now adds that dir to HKCU\Environment\Path on install and removes it on uninstall, via stock WordFunc.nsh (electron-builder's NSIS bundle has no EnVar plugin). It points at the real meshbay-node.exe dir — not a shim — so `where meshbay-node`, findNodeBinary and the W3 autostart launcher all resolve to the same binary. A WM_SETTINGCHANGE broadcast nudges open shells; new ones just work. Rebuilt: electron-builder --win nsis compiles the WordFunc includes fine, MeshBay-Setup-0.1.0.exe (155 MB). test_packaging_win.py covers the add/remove symmetry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: Windows installer (W4) — one per-user NSIS package, client + nodeChristophe Besson2026-09-041-0/+24
`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>