mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
249 lines
7.5 KiB
PowerShell
249 lines
7.5 KiB
PowerShell
# Uninstalls safe-chain from Windows
|
|
#
|
|
# Usage with "iex (iwr {url} -UseBasicParsing)" --> See README.md
|
|
|
|
# Use HOME on Unix, USERPROFILE on Windows (PowerShell Core is cross-platform)
|
|
$HomeDir = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE }
|
|
|
|
# Helper functions
|
|
function Write-Info {
|
|
param([string]$Message)
|
|
Write-Host "[INFO] $Message" -ForegroundColor Green
|
|
}
|
|
|
|
function Write-Warn {
|
|
param([string]$Message)
|
|
Write-Host "[WARN] $Message" -ForegroundColor Yellow
|
|
}
|
|
|
|
function Write-Error-Custom {
|
|
param([string]$Message)
|
|
Write-Host "[ERROR] $Message" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# Derives the safe-chain base install directory from a resolved binary path.
|
|
# Rejects wrapper scripts and paths that do not match the packaged bin layout.
|
|
function Get-InstallDirFromBinaryPath {
|
|
param([string]$BinaryPath)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($BinaryPath)) {
|
|
return $null
|
|
}
|
|
|
|
try {
|
|
$resolvedPath = (Resolve-Path -LiteralPath $BinaryPath -ErrorAction Stop).Path
|
|
}
|
|
catch {
|
|
$resolvedPath = [System.IO.Path]::GetFullPath($BinaryPath)
|
|
}
|
|
|
|
$fileName = [System.IO.Path]::GetFileName($resolvedPath)
|
|
if (($fileName -ne "safe-chain") -and ($fileName -ne "safe-chain.exe")) {
|
|
return $null
|
|
}
|
|
|
|
if ($resolvedPath -match '\.(js|cjs|mjs|cmd|ps1)$') {
|
|
return $null
|
|
}
|
|
|
|
$binDir = Split-Path -Parent $resolvedPath
|
|
if ((Split-Path -Leaf $binDir) -ne "bin") {
|
|
return $null
|
|
}
|
|
|
|
return (Split-Path -Parent $binDir)
|
|
}
|
|
|
|
# Returns the first safe-chain command found on PATH, if any.
|
|
# Used as the starting point for install-dir discovery.
|
|
function Get-SafeChainCommand {
|
|
return Get-Command safe-chain -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
}
|
|
|
|
# Returns the safe-chain command path only when it points to a valid packaged binary install.
|
|
# Prevents teardown from invoking arbitrary wrappers or scripts from PATH.
|
|
function Get-ValidatedSafeChainCommandPath {
|
|
$command = Get-SafeChainCommand
|
|
if (-not $command -or [string]::IsNullOrWhiteSpace($command.Path)) {
|
|
return $null
|
|
}
|
|
|
|
$installDir = Get-InstallDirFromBinaryPath -BinaryPath $command.Path
|
|
if (-not $installDir) {
|
|
return $null
|
|
}
|
|
|
|
return $command.Path
|
|
}
|
|
|
|
# Invokes the validated safe-chain binary with get-install-dir and returns the reported base directory.
|
|
# Safely returns $null when the command is unavailable or the lookup fails.
|
|
function Get-ReportedInstallDir {
|
|
$safeChainPath = Get-ValidatedSafeChainCommandPath
|
|
if (-not $safeChainPath) {
|
|
return $null
|
|
}
|
|
|
|
try {
|
|
$reportedInstallDir = & $safeChainPath get-install-dir 2>$null | Select-Object -First 1
|
|
if ($reportedInstallDir) {
|
|
$reportedInstallDir = $reportedInstallDir.Trim()
|
|
}
|
|
if ($reportedInstallDir) {
|
|
return $reportedInstallDir
|
|
}
|
|
}
|
|
catch {
|
|
return $null
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
# Determines the safe-chain base install directory for uninstall.
|
|
# Prefers the binary-reported location, then derives it from PATH, then falls back to the default home-dir layout.
|
|
function Get-SafeChainInstallDir {
|
|
$reportedInstallDir = Get-ReportedInstallDir
|
|
if ($reportedInstallDir) {
|
|
return $reportedInstallDir
|
|
}
|
|
|
|
$command = Get-SafeChainCommand
|
|
if ($command -and $command.Path) {
|
|
$discoveredInstallDir = Get-InstallDirFromBinaryPath -BinaryPath $command.Path
|
|
if ($discoveredInstallDir) {
|
|
return $discoveredInstallDir
|
|
}
|
|
}
|
|
|
|
return (Join-Path $HomeDir ".safe-chain")
|
|
}
|
|
|
|
# Finds the installed safe-chain binary inside the resolved install directory.
|
|
# Falls back to a validated safe-chain command when the expected file is missing.
|
|
function Find-SafeChainBinary {
|
|
param([string]$DotSafeChain)
|
|
|
|
$safeChainExe = Join-Path $DotSafeChain "bin/safe-chain.exe"
|
|
$safeChainBin = Join-Path $DotSafeChain "bin/safe-chain"
|
|
|
|
if (Test-Path $safeChainExe) {
|
|
return $safeChainExe
|
|
}
|
|
|
|
if (Test-Path $safeChainBin) {
|
|
return $safeChainBin
|
|
}
|
|
|
|
return Get-ValidatedSafeChainCommandPath
|
|
}
|
|
|
|
# Runs safe-chain teardown before removing the installation directory.
|
|
# Converts teardown failures into warnings so uninstall can still complete.
|
|
function Invoke-SafeChainTeardown {
|
|
param([string]$SafeChainPath)
|
|
|
|
if (-not $SafeChainPath) {
|
|
Write-Warn "safe-chain command not found. Proceeding with uninstallation."
|
|
return
|
|
}
|
|
|
|
Write-Info "Running safe-chain teardown..."
|
|
try {
|
|
& $SafeChainPath teardown
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Warn "safe-chain teardown encountered issues, continuing with uninstallation..."
|
|
}
|
|
}
|
|
catch {
|
|
Write-Warn "safe-chain teardown encountered issues: $_"
|
|
Write-Warn "Continuing with uninstallation..."
|
|
}
|
|
}
|
|
|
|
# Check and uninstall npm global package if present
|
|
function Remove-NpmInstallation {
|
|
# Check if npm is available
|
|
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
|
|
return
|
|
}
|
|
|
|
# Check if safe-chain is installed as an npm global package
|
|
npm list -g @aikidosec/safe-chain 2>&1 | Out-Null
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Info "Detected npm global installation of @aikidosec/safe-chain"
|
|
Write-Info "Uninstalling npm version before installing binary version..."
|
|
|
|
npm uninstall -g @aikidosec/safe-chain 2>&1 | Out-Null
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Info "Successfully uninstalled npm version"
|
|
}
|
|
else {
|
|
Write-Warn "Failed to uninstall npm version automatically"
|
|
Write-Warn "Please run: npm uninstall -g @aikidosec/safe-chain"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Check and uninstall Volta-managed package if present
|
|
function Remove-VoltaInstallation {
|
|
# Check if Volta is available
|
|
if (-not (Get-Command volta -ErrorAction SilentlyContinue)) {
|
|
return
|
|
}
|
|
|
|
# Volta manages global packages in its own directory
|
|
# Check if safe-chain is installed via Volta
|
|
volta list safe-chain 2>&1 | Out-Null
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Info "Detected Volta installation of @aikidosec/safe-chain"
|
|
Write-Info "Uninstalling Volta version before installing binary version..."
|
|
|
|
volta uninstall @aikidosec/safe-chain 2>&1 | Out-Null
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Info "Successfully uninstalled Volta version"
|
|
}
|
|
else {
|
|
Write-Warn "Failed to uninstall Volta version automatically"
|
|
Write-Warn "Please run: volta uninstall @aikidosec/safe-chain"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Main uninstallation
|
|
function Uninstall-SafeChain {
|
|
Write-Info "Uninstalling safe-chain..."
|
|
$DotSafeChain = Get-SafeChainInstallDir
|
|
$safeChainPath = Find-SafeChainBinary -DotSafeChain $DotSafeChain
|
|
Invoke-SafeChainTeardown -SafeChainPath $safeChainPath
|
|
|
|
# Remove npm and Volta installations
|
|
Remove-NpmInstallation
|
|
Remove-VoltaInstallation
|
|
|
|
# Remove .safe-chain directory
|
|
if (Test-Path $DotSafeChain) {
|
|
Write-Info "Removing installation directory: $DotSafeChain"
|
|
try {
|
|
Remove-Item -Path $DotSafeChain -Recurse -Force
|
|
Write-Info "Successfully removed installation directory"
|
|
}
|
|
catch {
|
|
Write-Error-Custom "Failed to remove $DotSafeChain : $_"
|
|
}
|
|
}
|
|
else {
|
|
Write-Info "Installation directory $DotSafeChain does not exist. Nothing to remove."
|
|
}
|
|
|
|
Write-Info "safe-chain has been uninstalled successfully!"
|
|
}
|
|
|
|
# Run uninstallation
|
|
try {
|
|
Uninstall-SafeChain
|
|
}
|
|
catch {
|
|
Write-Error-Custom "Uninstallation failed: $_"
|
|
}
|