; electron-builder NSIS customisation (auto-included: build/installer.nsh). ; ; Per-user install, no elevation at install time (package.json build.nsis) -- ; that part never changes. What this adds, all conditional on interactive setup ; (never ${Silent}): ; - the per-machine ("anyone who uses this computer") option removed from ; electron-builder's install-mode page: MeshBay is per-user only -- the ; keystore and the DPAPI-protected secrets are bound to the signed-in ; account (MESHBAY_DESIGN.md §11.2 / §7.5) -- so that option was only ever ; shown disabled here. customInstallMode forces current-user and the page ; is skipped entirely; ; - the bundled daemon dir on the user's PATH, so `meshbay-node` works in a ; terminal; ; - a custom page (radio buttons, like the rest of setup) choosing when the ; node runs: only while the MeshBay app is open, at each sign-in (a per-user ; Startup-folder launcher -- no admin -- see ; meshbay_node.platform.autostart_install), or as a background service ; (a boot-time S4U scheduled task -- one admin confirmation -- see ; meshbay_node.platform.service_install and packaging/win/service.ps1). ; Default: background service; ; - the inbound firewall rules, set up in EVERY mode (a node that silently ; accepts no connections is the failure mode called out in ; MESHBAY_DESIGN.md §7.5). Folded into the SAME elevation as the boot ; task when service mode is chosen; their own single elevation otherwise. ; One UAC prompt for an install, never two, never zero; ; - cleanup of whichever of those is outside $INSTDIR on the way out (the ; Startup .vbs; the scheduled task and firewall rules, together, if the ; user opts in at uninstall time). ; ; Deliberately NOT touched: ; - %LOCALAPPDATA%\meshbay\ (node.toml, keystore.enc, unlock.key, data/) -- ; the keystore must survive an uninstall/reinstall; installers place files, ; never remove secrets. This is also why service mode needs no code ; changes to platform.py: it runs as this same user (S4U), so it is the ; same profile either way. !include "WinMessages.nsh" !include "WordFunc.nsh" !include "LogicLib.nsh" !include "nsDialogs.nsh" !insertmacro WordAdd !insertmacro un.WordAdd !define MB_PWSH "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" ; The dir electron-builder drops resources into. `meshbay-node.exe` and its ; frozen Python live directly in here. A fixed suffix of $INSTDIR, so both the ; add (install) and the remove (uninstall, where $INSTDIR is still known) match ; the exact same string. !define MB_NODE_BIN "$INSTDIR\resources\node-runtime" ; ── force per-user, skip the all-users / current-user page ────────────────── !macro customInstallMode StrCpy $isForceCurrentInstall "1" !macroend !macro customInit StrCpy $MB_AutoMode "2" !macroend ; ── the autostart choice, as a radio page ───────────────────────────────── ; MB_AutoMode: "0" only-while-open, "1" at sign-in, "2" background service. ; Declared here (not at file scope) so the uninstaller pass -- which inserts ; none of the macros that touch it -- does not warn about an unused Var, which ; electron-builder's makensis promotes to a hard error. customInit defaults it ; for silent installs, where this page never runs. !macro customPageAfterChangeDir Var MB_AutoMode Var MB_Dlg Var MB_RbOpen Var MB_RbSignin Var MB_RbService Page custom mbAutostartPageCreate mbAutostartPageLeave Function mbAutostartPageCreate !insertmacro MUI_HEADER_TEXT "MeshBay Node" "Choose when the node runs on this computer." nsDialogs::Create 1018 Pop $MB_Dlg ${If} $MB_Dlg == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 26u "The node makes your groups' content available to other members. It can run only while the MeshBay window is open, start on its own when you sign in, or run as a background service that is up even before you sign in." Pop $0 ${NSD_CreateRadioButton} 6u 34u 96% 12u "Only while MeshBay is open" Pop $MB_RbOpen ${NSD_CreateRadioButton} 6u 48u 96% 12u "Automatically when I sign in to Windows" Pop $MB_RbSignin ${NSD_CreateRadioButton} 6u 62u 96% 12u "As a background service (starts at boot, before sign-in) -- recommended" Pop $MB_RbService ${NSD_CreateLabel} 0 82u 100% 34u "Setup adds Windows Firewall rules for local-network connections in every case. The background-service option, and those firewall rules, together need one administrator confirmation now -- without it the node cannot be reached and the app is not operational." Pop $0 ${If} $MB_AutoMode == "0" ${NSD_Check} $MB_RbOpen ${ElseIf} $MB_AutoMode == "1" ${NSD_Check} $MB_RbSignin ${Else} ${NSD_Check} $MB_RbService ${EndIf} nsDialogs::Show FunctionEnd Function mbAutostartPageLeave ${NSD_GetState} $MB_RbOpen $0 ${If} $0 == ${BST_CHECKED} StrCpy $MB_AutoMode "0" ${EndIf} ${NSD_GetState} $MB_RbSignin $0 ${If} $0 == ${BST_CHECKED} StrCpy $MB_AutoMode "1" ${EndIf} ${NSD_GetState} $MB_RbService $0 ${If} $0 == ${BST_CHECKED} StrCpy $MB_AutoMode "2" ${EndIf} FunctionEnd !macroend !macro customInstall ; resources\node-runtime\meshbay-node.exe is about to be overwritten; a ; daemon still running from a previous version holds the file open. nsExec::Exec 'taskkill /IM meshbay-node.exe /F' ; Add the daemon dir to the per-user PATH (HKCU\Environment). WordAdd is a ; stock NSIS macro over a ';'-delimited list -- it is a no-op if the entry is ; already there, so a reinstall does not double it. New shells only; the ; broadcast tells already-open Explorer/shells to reload the environment. ReadRegStr $0 HKCU "Environment" "Path" ${WordAdd} "$0" ";" "+${MB_NODE_BIN}" $1 WriteRegExpandStr HKCU "Environment" "Path" "$1" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ${IfNot} ${Silent} ; The firewall rules go in for every autostart mode. Read their state ; first, unelevated -- Get-NetFirewallRule needs no admin, only New/Remove ; do -- so an upgrade or repair that changes nothing triggers no UAC. nsExec::Exec '"${MB_PWSH}" -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\firewall.ps1" check' Pop $R0 ; 0 = every rule already present ${If} $MB_AutoMode == "2" ; Background service: the boot-time Scheduled Task AND the firewall ; rules, in ONE elevation (service-mode.ps1 does both). Skip it only ; when the task already exists and the rules are already there. nsExec::Exec '"${MB_PWSH}" -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service.ps1" status' Pop $R1 ; 0 = task installed ${If} $R1 == 0 ${AndIf} $R0 == 0 Goto mb_auto_done ${EndIf} ExecShellWait "runas" "${MB_PWSH}" \ '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service-mode.ps1" -Action install' \ SW_HIDE Goto mb_auto_done ${EndIf} ; Modes 0 and 1: no scheduled task. One elevation for the firewall rules, ; and only if one is actually missing. ${If} $R0 != 0 ExecShellWait "runas" "${MB_PWSH}" \ '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\firewall.ps1" add' \ SW_HIDE ${EndIf} ; Mode 1 also drops the per-user sign-in launcher (no admin -- it is just ; a .vbs in this account's Startup folder). Idempotent, so a repeat run is ; harmless. meshbay_node.platform.service_install() removes this itself if ; the user later switches to service mode from the Node page. ${If} $MB_AutoMode == "1" nsExec::Exec '"${MB_NODE_BIN}\meshbay-node.exe" autostart install' ${EndIf} mb_auto_done: ${EndIf} !macroend !macro customUnInstall nsExec::Exec 'taskkill /IM meshbay-node.exe /F' ; Take our entry back out of PATH, leaving the rest of it alone. ReadRegStr $0 HKCU "Environment" "Path" ${un.WordAdd} "$0" ";" "-${MB_NODE_BIN}" $1 WriteRegExpandStr HKCU "Environment" "Path" "$1" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ; Offer to take the firewall rules, and the service task if one was set up, ; back out together (needs admin again -- one prompt for both, same as ; install). Both underlying removes are no-ops when there is nothing to ; remove, so this is safe to run unconditionally regardless of which mode ; was chosen. Stale rules/tasks are inert if left, so this is opt-in and ; default-No; a silent uninstall skips it entirely. customUnInstall runs ; before the files are removed, so service-mode.ps1 is still there. ${IfNot} ${Silent} MessageBox MB_YESNO|MB_ICONQUESTION \ "Remove MeshBay's Windows Firewall rules and its boot-time service task, if you set one up? This needs one administrator confirmation. Both are harmless if left." \ /SD IDNO IDNO mb_keep_privileged ExecShellWait "runas" "${MB_PWSH}" \ '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service-mode.ps1" -Action remove' \ SW_HIDE mb_keep_privileged: ${EndIf} ; meshbay_node.platform.autostart_install() -- if the user picked "at sign-in" ; (here, or later in the client), this points wscript at the binary we are ; about to delete, and would error at every sign-in. Delete "$APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\MeshBay Node.vbs" !macroend