aboutsummaryrefslogtreecommitdiffstats
path: root/packaging/win
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-04 15:36:53 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-04 15:36:53 +0200
commit74941aae5451c03a296413710fe888b1924e8c27 (patch)
tree8dda07ea4f7c909122650a829447b871ca5b0997 /packaging/win
parentd04b915580c8ba05beb0943a6fab9b04e12294e4 (diff)
downloadmeshbay-74941aae5451c03a296413710fe888b1924e8c27.tar.gz
feat(packaging): offer one elevated firewall step instead of two dialogs
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>
Diffstat (limited to 'packaging/win')
-rw-r--r--packaging/win/README.md23
-rw-r--r--packaging/win/firewall.ps168
2 files changed, 83 insertions, 8 deletions
diff --git a/packaging/win/README.md b/packaging/win/README.md
index 8c29785..7bd7f67 100644
--- a/packaging/win/README.md
+++ b/packaging/win/README.md
@@ -11,6 +11,7 @@ Linux). `meshbay-common` rides along inside the node runtime.
├─ MeshBay.exe Electron client
├─ resources\
│ ├─ app.asar src/ + ui/ (the interface ships in the package)
+│ ├─ firewall.ps1 adds/removes the two inbound rules (see below)
│ └─ node-runtime\
│ ├─ meshbay-node.exe frozen daemon (PyInstaller onedir)
│ ├─ _internal\ … its Python + deps (aiortc, av, aioquic, …)
@@ -88,14 +89,20 @@ publish their host candidate as an unresolvable `<uuid>.local` mDNS name that
`aioice` discards — the browser always dials the node, never the reverse. So the
node has to accept unsolicited inbound UDP from its peers.
-**Windows Defender Firewall.** On the daemon's first run Windows pops a prompt
-for `meshbay-node.exe`. Tick **both Private and Public** — a libvirt/VM adapter,
-and sometimes a plain Ethernet one, registers as Public, and a Private-only rule
-then silently drops every peer. The installer cannot pre-create this rule (it is
-per-user and never elevates); the prompt is the mechanism. If you dismissed it,
-add the rule by hand: *Windows Defender Firewall → Advanced → Inbound Rules →
-New Rule → Program →* the bundled `…\resources\node-runtime\meshbay-node.exe` *→
-Allow → all profiles*.
+**Windows Defender Firewall.** The setup wizard offers to add the inbound rules
+for `MeshBay.exe` and `meshbay-node.exe` in one step — it needs one admin
+confirmation (`build/installer.nsh` runs `firewall.ps1` via NSIS `ExecShellWait
+"runas"`; the per-user install itself never elevates). Say yes and both
+prompts you'd otherwise hit mid-use are gone; say no, or the UAC prompt is
+dismissed, and Windows falls back to its own **"Allow access"** dialog the
+first time each process binds a socket — tick **both Private and Public** then
+(a libvirt/VM adapter, and sometimes a plain Ethernet one, registers as
+Public; a Private-only rule silently drops every peer). Missed both? Add it by
+hand: *Windows Defender Firewall → Advanced → Inbound Rules → New Rule →
+Program →* the bundled `…\resources\node-runtime\meshbay-node.exe` *→ Allow →
+all profiles*. `firewall.ps1` is idempotent and re-runnable
+(`powershell -File resources\firewall.ps1 add`, elevated); it logs to
+`%TEMP%\meshbay-firewall.log`.
**A flat LAN needs nothing else.** The node offers a routable `192.168.x.y` host
candidate and browsers on the same subnet connect straight to it — same as the
diff --git a/packaging/win/firewall.ps1 b/packaging/win/firewall.ps1
new file mode 100644
index 0000000..abed109
--- /dev/null
+++ b/packaging/win/firewall.ps1
@@ -0,0 +1,68 @@
+<#
+.SYNOPSIS
+ Add (or remove) the inbound Windows Firewall rules MeshBay needs.
+
+.DESCRIPTION
+ WebRTC binds an ephemeral UDP port per connection and the browser always
+ dials the node (aioice cannot resolve the peer's mDNS `.local` candidate),
+ so the node must accept unsolicited inbound UDP. Without a rule, Windows
+ pops an "Allow access" dialog the first time each of MeshBay.exe and
+ meshbay-node.exe binds a socket.
+
+ The installer runs this once, elevated, so the user answers one UAC prompt
+ instead of two firewall dialogs later. Declining the installer's offer is
+ fine -- the dialogs are the fallback.
+
+ Shipped as an extraResource at <install>\resources\firewall.ps1, so it
+ locates the two executables from its own path and takes no arguments beyond
+ the action. Runs elevated and windowless, so it leaves a trace at
+ %TEMP%\meshbay-firewall.log.
+
+.PARAMETER Action
+ add (default) create/replace the rules
+ remove delete them
+#>
+[CmdletBinding()]
+param(
+ [ValidateSet("add", "remove")]
+ [string]$Action = "add"
+)
+
+$ErrorActionPreference = "Stop"
+$log = Join-Path $env:TEMP "meshbay-firewall.log"
+"[{0}] {1}" -f (Get-Date -Format s), $Action | Add-Content $log
+
+# This script sits at <install>\resources\firewall.ps1.
+$resources = $PSScriptRoot
+$install = Split-Path -Parent $resources
+$GROUP = "MeshBay"
+
+$targets = @(
+ @{ Name = "MeshBay"; Path = Join-Path $install "MeshBay.exe" }
+ @{ Name = "MeshBay Node"; Path = Join-Path $resources "node-runtime\meshbay-node.exe" }
+)
+
+try {
+ foreach ($t in $targets) {
+ # Idempotent: clear any existing rule of this name first.
+ Remove-NetFirewallRule -DisplayName $t.Name -ErrorAction SilentlyContinue
+
+ if ($Action -eq "add") {
+ if (-not (Test-Path $t.Path)) {
+ " skip $($t.Name): $($t.Path) not found" | Add-Content $log
+ continue
+ }
+ New-NetFirewallRule -DisplayName $t.Name -Group $GROUP `
+ -Direction Inbound -Action Allow `
+ -Program $t.Path -Protocol UDP -Profile Any | Out-Null
+ " allowed $($t.Name) ($($t.Path))" | Add-Content $log
+ }
+ else {
+ " removed $($t.Name)" | Add-Content $log
+ }
+ }
+}
+catch {
+ " ERROR: $_" | Add-Content $log
+ throw
+}