Skip to content

Commit

Permalink
Remove all Machine handling of path modification, ensure to safely …
Browse files Browse the repository at this point in the history
…modify path
  • Loading branch information
confused-Techie committed Mar 18, 2024
1 parent 3411fb7 commit 90d71d0
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 153 deletions.
83 changes: 21 additions & 62 deletions packages/settings-view/lib/system-windows-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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 (
<div className='control-group'>
<div className='controls'>
<div className='checkbox'>
<label for='system.windows.add-to-path'>
<input
ref='addToPathCheckbox'
id='system.windows.add-to-path'
className='input-checkbox'
type='checkbox'
onclick={(e) => {
this.setRegistration(WinShell.pathUser, e.target.checked)
}} />
<div className='setting-title'>Add Pulsar to PATH (User Install)</div>
<div className='setting-description'>
Add Pulsar to Windows PATH to enable CLI usage.
</div>
</label>
</div>
</div>
</div>
);
} else {
return (
<div className='control-group'>
<div className='controls'>
<div className='checkbox'>
<label for='system.windows.add-to-path-machine'>
<input
ref='addToPathMachineCheckbox'
id='system.windows.add-to-path-machine'
className='input-checkbox'
type='checkbox'
onclick={(e) => {
this.setRegistration(WinShell.pathMachine, e.target.checked)
}} />
<div className='setting-title'>Add Pulsar to PATH (Machine Install)</div>
<div className='setting-description'>
Add Pulsar to Windows PATH for machine installs. Requires administrative privileges.
</div>
</label>
</div>
return (
<div className='control-group'>
<div className='controls'>
<div className='checkbox'>
<label for='system.windows.add-to-path'>
<input
ref='addToPathCheckbox'
id='system.windows.add-to-path'
className='input-checkbox'
type='checkbox'
onclick={(e) => {
this.setRegistration(WinShell.pathUser, e.target.checked)
}} />
<div className='setting-title'>Add Pulsar to PATH</div>
<div className='setting-description'>
Add Pulsar to Windows PATH to enable CLI usage.
</div>
</label>
</div>
</div>
);
}
</div>
);
}

focus () {
Expand Down
127 changes: 62 additions & 65 deletions resources/win/modifyWindowsPath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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.";
}
}
36 changes: 10 additions & 26 deletions src/main-process/win-shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) =>
{
Expand All @@ -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) =>
{
Expand Down Expand Up @@ -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);
}
});
});
Expand Down Expand Up @@ -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");

0 comments on commit 90d71d0

Please sign in to comment.