From 9bd581ee03b02dca8b80a6021c6e9921b76ef9a3 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Mon, 3 Aug 2026 01:17:00 +0100 Subject: [PATCH] Refactor Windows installer and scripts to enhance user access and installation behavior - Updated `package.json` to change installation scope from `perMachine` to `perUser`, allowing installations for standard users without admin rights. - Modified `farmcontrol.nsi` to adjust installation directory and registry keys to use `HKCU` instead of `HKLM`, improving accessibility for non-admin users. - Refined `installer.nsh` and related scripts to ensure proper handling of the farmcontrol URI handler and shortcuts, aligning with the new user access model. - Removed references to the `grant-users-access.nsh` script, as user access permissions are now managed directly within the installer. --- package.json | 6 ++--- packaging/windows/farmcontrol.nsi | 26 +++++++++---------- packaging/windows/installer.nsh | 42 ++++++++++++++++++++----------- packaging/windows/msi-wrapped.wxs | 18 ++++++------- scripts/build-windows-nsis.ps1 | 2 -- scripts/installer.nsh | 22 +++++++--------- src/desktop/updater-runner.js | 32 +++++++++++++++-------- 7 files changed, 81 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index 1460766..7c36795 100644 --- a/package.json +++ b/package.json @@ -245,12 +245,12 @@ "oneClick": false, "allowToChangeInstallationDirectory": true, "include": "scripts/installer.nsh", - "perMachine": true + "perMachine": false }, "msiWrapped": { "upgradeCode": "{735812DB-E33B-57A0-8FBC-5FC3155925AA}", - "perMachine": true, - "impersonate": false, + "perMachine": false, + "impersonate": true, "wrappedInstallerArgs": "/S" } } diff --git a/packaging/windows/farmcontrol.nsi b/packaging/windows/farmcontrol.nsi index f376a24..f3e27fc 100644 --- a/packaging/windows/farmcontrol.nsi +++ b/packaging/windows/farmcontrol.nsi @@ -20,9 +20,9 @@ Name "Farm Control" OutFile "${OUTFILE}" -InstallDir "$PROGRAMFILES64\Farm Control" -InstallDirRegKey HKLM "Software\Tom Butcher\Farm Control" "InstallDir" -RequestExecutionLevel admin +InstallDir "$LOCALAPPDATA\Programs\Farm Control" +InstallDirRegKey HKCU "Software\Tom Butcher\Farm Control" "InstallDir" +RequestExecutionLevel user !define MUI_ABORTWARNING @@ -58,23 +58,21 @@ Section "Farm Control" SecMain !insertmacro customInstall - WriteRegStr HKLM "Software\Tom Butcher\Farm Control" "InstallDir" $INSTDIR - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegStr HKCU "Software\Tom Butcher\Farm Control" "InstallDir" $INSTDIR + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "DisplayName" "Farm Control" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "DisplayVersion" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "Publisher" "Tom Butcher" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "UninstallString" "$INSTDIR\Uninstall.exe" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ "NoRepair" 1 WriteUninstaller "$INSTDIR\Uninstall.exe" - - !insertmacro grantUsersInstallAccess SectionEnd Section "Uninstall" @@ -83,6 +81,6 @@ Section "Uninstall" Delete "$INSTDIR\Uninstall.exe" RMDir /r "$INSTDIR" - DeleteRegKey HKLM "Software\Tom Butcher\Farm Control" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" + DeleteRegKey HKCU "Software\Tom Butcher\Farm Control" + DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" SectionEnd diff --git a/packaging/windows/installer.nsh b/packaging/windows/installer.nsh index 0e5fb91..e3b6fa3 100644 --- a/packaging/windows/installer.nsh +++ b/packaging/windows/installer.nsh @@ -5,16 +5,30 @@ !macro uninstallPreviousFarmControl ClearErrors - ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString" + ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString" StrCmp $R0 "" check_install_dir run_uninstall check_install_dir: + ReadRegStr $R0 HKCU "Software\Tom Butcher\Farm Control" "InstallDir" + StrCmp $R0 "" check_legacy_uninstall + StrCpy $R0 "$R0\Uninstall.exe" + Goto run_uninstall + + check_legacy_uninstall: + ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString" + StrCmp $R0 "" check_legacy_install_dir run_uninstall + + check_legacy_install_dir: ReadRegStr $R0 HKLM "Software\Tom Butcher\Farm Control" "InstallDir" StrCmp $R0 "" check_default_dir StrCpy $R0 "$R0\Uninstall.exe" Goto run_uninstall check_default_dir: + StrCpy $R0 "$LOCALAPPDATA\Programs\Farm Control\Uninstall.exe" + IfFileExists $R0 run_uninstall check_legacy_default_dir + + check_legacy_default_dir: StrCpy $R0 "$PROGRAMFILES64\Farm Control\Uninstall.exe" IfFileExists $R0 run_uninstall done_uninstall @@ -52,40 +66,38 @@ !macroend !macro createDesktopShortcut - SetShellVarContext all + SetShellVarContext current CreateShortCut "$DESKTOP\Farm Control.lnk" "$INSTDIR\bin\launcher.exe" "" "$INSTDIR\bin\launcher.exe" 0 SW_SHOWNORMAL "" "Farm Control" !insertmacro fixShortcutWorkingDir "$DESKTOP\Farm Control.lnk" "$INSTDIR\bin" !macroend !macro createStartMenuShortcut - SetShellVarContext all + SetShellVarContext current CreateDirectory "$SMPROGRAMS\Farm Control" CreateShortCut "$SMPROGRAMS\Farm Control\Farm Control.lnk" "$INSTDIR\bin\launcher.exe" "" "$INSTDIR\bin\launcher.exe" 0 SW_SHOWNORMAL "" "Farm Control" !insertmacro fixShortcutWorkingDir "$SMPROGRAMS\Farm Control\Farm Control.lnk" "$INSTDIR\bin" !macroend !macro removeDesktopShortcut - SetShellVarContext all + SetShellVarContext current Delete "$DESKTOP\Farm Control.lnk" !macroend !macro removeStartMenuShortcut - SetShellVarContext all + SetShellVarContext current Delete "$SMPROGRAMS\Farm Control\Farm Control.lnk" RMDir "$SMPROGRAMS\Farm Control" !macroend -!include "grant-users-access.nsh" - !macro customInstall DetailPrint "Register farmcontrol URI Handler" - DeleteRegKey HKCR "farmcontrol" - WriteRegStr HKCR "farmcontrol" "" "URL:farmcontrol" - WriteRegStr HKCR "farmcontrol" "URL Protocol" "" - WriteRegStr HKCR "farmcontrol\DefaultIcon" "" "$INSTDIR\bin\launcher.exe" - WriteRegStr HKCR "farmcontrol\shell" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open\command" "" '"$INSTDIR\bin\bun.exe" "$INSTDIR\bin\deeplink.js" "%1"' + DeleteRegKey HKCU "Software\Classes\farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "" "URL:farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\DefaultIcon" "" "$INSTDIR\bin\launcher.exe" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open\command" "" '"$INSTDIR\bin\bun.exe" "$INSTDIR\bin\deeplink.js" "%1"' DetailPrint "Creating shortcuts" !insertmacro createDesktopShortcut @@ -95,5 +107,5 @@ !macro customUnInstall !insertmacro removeDesktopShortcut !insertmacro removeStartMenuShortcut - DeleteRegKey HKCR "farmcontrol" + DeleteRegKey HKCU "Software\Classes\farmcontrol" !macroend diff --git a/packaging/windows/msi-wrapped.wxs b/packaging/windows/msi-wrapped.wxs index ff9298b..6dd3a51 100644 --- a/packaging/windows/msi-wrapped.wxs +++ b/packaging/windows/msi-wrapped.wxs @@ -10,7 +10,7 @@ = 601]]> @@ -28,7 +28,7 @@ @@ -37,7 +37,7 @@ @@ -49,24 +49,24 @@ Id="KillFarmControl" BinaryKey="WixCA" DllEntry="WixQuietExec" - Execute="deferred" - Impersonate="no" + Execute="immediate" + Impersonate="yes" Return="ignore" /> diff --git a/scripts/build-windows-nsis.ps1 b/scripts/build-windows-nsis.ps1 index 7f5270d..fdcf0ec 100644 --- a/scripts/build-windows-nsis.ps1 +++ b/scripts/build-windows-nsis.ps1 @@ -48,7 +48,6 @@ function Get-DirectoryBytes { $rootDir = Split-Path -Parent $PSScriptRoot $nsiPath = Join-Path $rootDir "packaging/windows/farmcontrol.nsi" $installerInclude = Join-Path $rootDir "packaging/windows/installer.nsh" -$grantUsersAccessInclude = Join-Path $rootDir "packaging/windows/grant-users-access.nsh" $workDir = Join-Path $env:TEMP "farmcontrol-nsis" $localInstallerName = "farmcontrol-installer.exe" @@ -81,7 +80,6 @@ if (-not (Test-Path $requiredDeeplinkScript)) { Copy-Item -LiteralPath $nsiPath -Destination (Join-Path $workDir "farmcontrol.nsi") Copy-Item -LiteralPath $installerInclude -Destination (Join-Path $workDir "installer.nsh") -Copy-Item -LiteralPath $grantUsersAccessInclude -Destination (Join-Path $workDir "grant-users-access.nsh") $iconPath = Join-Path $rootDir "assets\installer.ico" if (Test-Path $iconPath) { diff --git a/scripts/installer.nsh b/scripts/installer.nsh index 7d58b96..d999278 100644 --- a/scripts/installer.nsh +++ b/scripts/installer.nsh @@ -1,14 +1,10 @@ -!include "packaging\windows\grant-users-access.nsh" - -!macro customInstall - !insertmacro grantUsersInstallAccess - +!macro customInstall DetailPrint "Register farmcontrol URI Handler" - DeleteRegKey HKCR "farmcontrol" - WriteRegStr HKCR "farmcontrol" "" "URL:farmcontrol" - WriteRegStr HKCR "farmcontrol" "URL Protocol" "" - WriteRegStr HKCR "farmcontrol\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" - WriteRegStr HKCR "farmcontrol\shell" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1" -!macroend \ No newline at end of file + DeleteRegKey HKCU "Software\Classes\farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "" "URL:farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1" +!macroend diff --git a/src/desktop/updater-runner.js b/src/desktop/updater-runner.js index 567ee2f..22ef8b6 100644 --- a/src/desktop/updater-runner.js +++ b/src/desktop/updater-runner.js @@ -5,10 +5,13 @@ import path from 'node:path' import process from 'node:process' const MAC_APP_NAME = 'Farm Control.app' -const WINDOWS_INSTALL_DIR_KEY = +const WINDOWS_INSTALL_DIR_KEYS = [ + 'HKCU\\Software\\Tom Butcher\\Farm Control', 'HKLM\\Software\\Tom Butcher\\Farm Control' +] const WINDOWS_DEFAULT_LAUNCHER = path.join( - process.env.ProgramFiles || 'C:\\Program Files', + process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), + 'Programs', 'Farm Control', 'bin', 'launcher.exe' @@ -39,16 +42,23 @@ const findMacAppBundle = (startPath) => { } const readWindowsInstallDirFromRegistry = () => { - try { - const output = execSync( - `reg query ${quoteBatchArg(WINDOWS_INSTALL_DIR_KEY)} /v InstallDir`, - { encoding: 'utf8', windowsHide: true } - ) - const match = output.match(/InstallDir\s+REG_\w+\s+(.+)/i) - return match?.[1]?.trim() || null - } catch { - return null + for (const registryKey of WINDOWS_INSTALL_DIR_KEYS) { + try { + const output = execSync( + `reg query ${quoteBatchArg(registryKey)} /v InstallDir`, + { encoding: 'utf8', windowsHide: true } + ) + const match = output.match(/InstallDir\s+REG_\w+\s+(.+)/i) + const installDir = match?.[1]?.trim() + if (installDir) { + return installDir + } + } catch { + // Try the next registry key. + } } + + return null } export const resolveAppLaunchPath = () => {