From 90d71d0391de7b81a2de1b8a879a59f56133f975 Mon Sep 17 00:00:00 2001 From: confused-Techie Date: Sun, 17 Mar 2024 23:54:48 -0700 Subject: [PATCH] Remove all `Machine` handling of path modification, ensure to safely modify path --- .../settings-view/lib/system-windows-panel.js | 83 +++--------- resources/win/modifyWindowsPath.ps1 | 127 +++++++++--------- src/main-process/win-shell.js | 36 ++--- 3 files changed, 93 insertions(+), 153 deletions(-) diff --git a/packages/settings-view/lib/system-windows-panel.js b/packages/settings-view/lib/system-windows-panel.js index 439e7b5894..6ba1e11234 100644 --- a/packages/settings-view/lib/system-windows-panel.js +++ b/packages/settings-view/lib/system-windows-panel.js @@ -20,14 +20,7 @@ export default class SystemPanel { WinShell.fileHandler.isRegistered((i) => { this.refs.fileHandlerCheckbox.checked = i }) WinShell.fileContextMenu.isRegistered((i) => { this.refs.fileContextMenuCheckbox.checked = i }) WinShell.folderContextMenu.isRegistered((i) => { this.refs.folderContextMenuCheckbox.checked = i }) - - if (this.isLikelyUserInstall()) { - WinShell.pathUser.isRegistered((i) => { this.refs.addToPathCheckbox.checked = i }) - } else { - WinShell.pathMachine.isRegistered((i) => { this.refs.addToPathMachineCheckbox.checked = i }) - // Check if Pulsar is running as Admin. To know if the user can modify the machine path - WinShell.runningAsAdmin((i) => { this.refs.addToPathMachineCheckbox.disabled = !i }) - } + WinShell.pathUser.isRegistered((i) => { this.refs.addToPathCheckbox.checked = i }) } destroy () { @@ -120,63 +113,29 @@ export default class SystemPanel { } } - isLikelyUserInstall() { - let resourcePath = atom.applicationDelegate.getWindowLoadSettings().resourcePath; - if (resourcePath.includes("AppData\\Local\\Programs\\pulsar")) { - return true; - } else { - return false; - } - } - getPathUI() { - if (this.isLikelyUserInstall()) { - return ( -
-
-
- -
-
-
- ); - } else { - return ( -
-
-
- -
+ return ( +
+
+
+
- ); - } +
+ ); } focus () { diff --git a/resources/win/modifyWindowsPath.ps1 b/resources/win/modifyWindowsPath.ps1 index f02be5f1e9..ab7c5cd66d 100644 --- a/resources/win/modifyWindowsPath.ps1 +++ b/resources/win/modifyWindowsPath.ps1 @@ -3,97 +3,94 @@ # Example Usage: # Pulsar User Installation: -# .\_.ps1 -installMode User -installdir "$INSTDIR" -remove 0 +# .\_.ps1 -installdir "$INSTDIR" -remove 0 # Pulsar Machine Installation: -# .\_.ps1 -installMode Machine -installdir "$INSTDIR" -remove 0 +# .\_.ps1 -installdir "$INSTDIR" -remove 0 # Pulsar User Uninstallation: -# .\_.ps1 -installMode User -installdir "$INSTDIR" -remove 1 +# .\_.ps1 -installdir "$INSTDIR" -remove 1 # Pulsar Machine Uninstallation: -# .\_.ps1 -installMode Machine -installdir "$INSTDIR" -remove 1 +# .\_.ps1 -installdir "$INSTDIR" -remove 1 -param ($installMode,$installdir,$remove) +# For safe interaction with environment variables taken from: +# https://github.com/chocolatey/choco/blob/HEAD/src/chocolatey.resources/helpers/functions/Set-EnvironmentVariable.ps1 +# https://github.com/chocolatey/choco/blob/HEAD/src/chocolatey.resources/helpers/functions/Get-EnvironmentVariable.ps1 +# https://github.com/chocolatey/choco/blob/HEAD/src/chocolatey.resources/helpers/functions/Install-ChocolateyPath.ps1 + +param ($installdir,$remove) # When self-elevating, we can't pass a raw boolean. Meaning we accept anything then convert $remove = [System.Convert]::ToBoolean($remove) -# Only when modifying the Machine PATH, it takes much longer than expected. So here's a loading bar -$prog = 1 -Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog +if (-not $remove) { + # We want to add Pulsar path values -if ($installMode -eq "Machine") { - # PowerShell needs to be running as Admin to modify the Machine Variables - # So lets attempt to self-elevate - if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { - if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { + # Lets first save a copy of the users current path + $env:Path >> prior2addition.txt; - $processOptions = @{ - FilePath = "PowerShell.exe" - Wait = $true - PassThru = $true - Verb = "RunAs" - ArgumentList = "-File `"" + $MyInvocation.MyCommand.Path + "`" -installMode $installMode -installdir `"" + $installdir + "`" -remove $remove" - } + $originalPathToInstall = $installdir - Start-Process @processOptions + $pulsarPath = $installdir + "\resources"; + $ppmPath = $installdir + "\resources\app\ppm\bin"; - Exit - } - } -} + # Get the current PATH variable + $envPath = $env:PATH; + if (!$envPath.toLower().Contains($installdir.ToLower())) { + # we don't already have the correct environment variable + $actualPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User); -if (-not $remove) { - if ($installMode -eq "User" -or $installMode -eq "Machine") { + $statementTerminator = ";"; - $prog = 25 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $pathToInstall = $pulsarPath + $statementTerminator + $ppmPath + $statementTerminator; - [Environment]::SetEnvironmentVariable("Path", $env:Path + ";$installdir\resources;$installdir\resources\app\ppm\bin", $installMode) + # Does the path end in ';'? + $hasStatementTerminator = $actualPath -ne $null -and $actualPath.EndsWith($statementTerminator); + # If the last digit is not ';', then add it + if (!$hasStatementTerminator -and $actualPath -ne $null) { + $pathToInstall = $statementTerminator + $pathToInstall; + } - $prog = 50 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $actualPath = $actualPath + $pathToInstall; - # While this originally attempting to use the string '%USERPROFILE%' to avoid taking - # space on the PATH, whatever reads this path at startup in Pulsar, can't handle - # the variable, and instead creates the directory of the same name - # within the current folder. But only when opened via the context menu, terminal - # is fine. - $exitCode = [Environment]::SetEnvironmentVariable("ATOM_HOME", "$env:UserProfile\.pulsar", $installMode) + # Now to actually set the path to the system + $registryType = [Microsoft.Win32.RegistryValueKind]::ExpandString; + $keyHive = "HKEY_CURRENT_USER"; + $registryKey = "Environment"; - $prog = 100 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $exitCode = [Microsoft.Win32.Registry]::SetValue($keyHive + "\" + $registryKey, "Path", $actualPath, [System.EnvironmentVariableTarget]::User); - Exit $exitCode + Exit $exitCode; + } else { + Write-Host "Pulsar is already present on the User PATH."; } -} else { - if ($installMode -eq "User" -or $installMode -eq "Machine") { - - $prog = 25 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog - $path = [Environment]::GetEnvironmentVariable("Path", $installMode) - - $prog = 50 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog +} else { + # We want to remove Pulsar from the user path - # Remove unwanted element from path - $path = ($path.Split(";") | Where-Object { $_ -ne "$installdir\resources" }) -join ";" - $path = ($path.Split(";") | Where-Object { $_ -ne "$installdir\resources\app\ppm\bin" }) -join ";" + # Lets first save a copy of the users current path + $env:Path >> prior2removal.txt; - $prog = 75 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $pulsarPath = $installdir + "\resources"; + $ppmPath = $installdir + "\resources\app\ppm\bin"; - # Set our new path - [Environment]::SetEnvironmentVariable("Path", $path, $installMode) + # Get the current PATH variable + $envPath = $env:PATH; + if ($envPath.toLower().Contains($installdir.ToLower())) { + # the install dir is in fact on the path + $actualPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User); - $prog = 90 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $actualPath = ($actualPath.Split(";") | Where-Object { $_ -ne $ppmPath }) -join ";"; + # Order is important, as Pulsar's path INCLUDES ppm's path + $actualPath = ($actualPath.Split(";") | Where-Object { $_ -ne $pulsarPath }) -join ";"; - # Set ATOM_HOME path - $exitCode = [Environment]::SetEnvironmentVariable("ATOM_HOME", $null, $installMode) + # Now to actually set the path to the system + $registryType = [Microsoft.Win32.RegistryValueKind]::ExpandString; + $keyHive = "HKEY_CURRENT_USER"; + $registryKey = "Environment"; - $prog = 100 - Write-Progress -Activity "Modifying Pulsar ($installdir) on the PATH..." -Status "$prog% Complete:" -PercentComplete $prog + $exitCode = [Microsoft.Win32.Registry]::SetValue($keyHive + "\" + $registryKey, "Path", $actualPath, [System.EnvironmentVariableTarget]::User); - Exit $exitCode - } # Else we have been given bad params, and will silently exit + Exit $exitCode; + } else { + Write-Host "Pulsar is not present on the User PATH."; + } } diff --git a/src/main-process/win-shell.js b/src/main-process/win-shell.js index 05353d064d..d3d41d2b49 100644 --- a/src/main-process/win-shell.js +++ b/src/main-process/win-shell.js @@ -74,27 +74,17 @@ class ShellOption { } class PathOption { - constructor(installType) { - // installType MUST be 'User' or 'Machine' + constructor() { this.HKPATH; this.hive; this.installReg = "\\SOFTWARE\\0949b555-c22c-56b7-873a-a960bdefa81f"; this.installMode = installType; - if (installType === "User") { - this.HKPATH = "\\Environment"; - this.hive = "HKCU"; - } else if (installType === "Machine") { - this.HKPATH = "\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"; - this.hive = "HKLM"; - } + // We no longer support an `installType` + // Only managing the path of the current user + this.HKPATH = "\\Environment"; + this.hive = "HKCU"; - // Unfortunately, we can only manage the PATH for a per user installation. - // While the PowerShell script does support setting the PATH for a Machine - // install, we can't yet check that. - // https://github.com/fresc81/node-winreg/tree/1.2.1#troubleshooting - // This can only be done if Pulsar is run as Admin, with a user with Admin privs - // So we will pretend a user install is all that matters here this.isRegistered = this.isRegistered.bind(this); this.register = this.register.bind(this); this.deregister = this.deregister.bind(this); @@ -129,8 +119,8 @@ class PathOption { register(callback) { this.getPulsarPath().then((pulsarPath) => { const child = ChildProcess.execFile( - `${pulsarPath}\\resources\\modifyWindowsPath.ps1`, - ['-installMode', this.installMode, '-installdir', `"${pulsarPath}"`, '-remove', '0'], + `"${pulsarPath}\\resources\\modifyWindowsPath.ps1"`, + ['-installdir', `"${pulsarPath}"`, '-remove', '0'], { shell: "powershell.exe" }, (error, stdout, stderr) => { @@ -151,8 +141,8 @@ class PathOption { if (isRegistered) { this.getPulsarPath().then((pulsarPath) => { const child = ChildProcess.execFile( - `${pulsarPath}\\resources\\modifyWindowsPath.ps1`, - ['-installMode', this.installMode, '-installdir', `"${pulsarPath}"`, '-remove', '1'], + `"${pulsarPath}\\resources\\modifyWindowsPath.ps1"`, + ['-installdir', `"${pulsarPath}"`, '-remove', '1'], { shell: "powershell.exe" }, (error, stdout, stderr) => { @@ -188,12 +178,7 @@ class PathOption { reject("Unable to find Pulsar Install Path"); } - // When we are modifying Machine values, we can't accept spaces in the - // path. There's likely some combination of escapes to fix this, but - // I was unable to find them. For now we will check for the default - // Machine install location, and remove the space. - let safePulsarPath = pulsarPath.replace("Program Files", "PROGRA~1"); - resolve(safePulsarPath); + resolve(pulsarPath); } }); }); @@ -241,4 +226,3 @@ exports.folderBackgroundContextMenu = new ShellOption( JSON.parse(JSON.stringify(contextParts).replace('%1', '%V')) ); exports.pathUser = new PathOption("User"); -exports.pathMachine = new PathOption("Machine");