From 99e822d5099fcc649c75736b86a9ffba6bb68a76 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 30 Mar 2026 12:03:36 +0200 Subject: [PATCH] Rename safe-chain ultimate to Aikido Endpoint --- install-scripts/install-endpoint-mac.sh | 14 +- install-scripts/install-endpoint-windows.ps1 | 14 +- install-scripts/uninstall-endpoint-mac.sh | 10 +- .../uninstall-endpoint-windows.ps1 | 12 +- .../src/installation/downloadAgent.js | 125 ----------- .../src/installation/downloadAgent.spec.js | 56 ----- .../src/installation/installOnMacOS.js | 155 ------------- .../src/installation/installOnWindows.js | 203 ------------------ .../src/installation/installUltimate.js | 35 --- 9 files changed, 25 insertions(+), 599 deletions(-) mode change 100644 => 100755 install-scripts/install-endpoint-mac.sh mode change 100644 => 100755 install-scripts/uninstall-endpoint-mac.sh delete mode 100644 packages/safe-chain/src/installation/downloadAgent.js delete mode 100644 packages/safe-chain/src/installation/downloadAgent.spec.js delete mode 100644 packages/safe-chain/src/installation/installOnMacOS.js delete mode 100644 packages/safe-chain/src/installation/installOnWindows.js delete mode 100644 packages/safe-chain/src/installation/installUltimate.js diff --git a/install-scripts/install-endpoint-mac.sh b/install-scripts/install-endpoint-mac.sh old mode 100644 new mode 100755 index 684a8a8..9f3b1c0 --- a/install-scripts/install-endpoint-mac.sh +++ b/install-scripts/install-endpoint-mac.sh @@ -1,14 +1,14 @@ #!/bin/sh -# Downloads and installs SafeChain Ultimate endpoint on macOS +# Downloads and installs Aikido Endpoint Protection on macOS # # Usage: curl -fsSL | sudo sh -s -- --token set -e # Exit on error # Configuration -INSTALL_URL="https://github.com/AikidoSec/safechain-internals/releases/download/v1.2.5/SafeChainUltimate.pkg" -DOWNLOAD_SHA256="abc2b0e6c6a4ca33cd893eeb16744f9f2da90013fb1abac301f5c00c2ad8bc30" +INSTALL_URL="https://github.com/AikidoSec/safechain-internals/releases/download/v1.2.7/EndpointProtection.pkg" +DOWNLOAD_SHA256="2c180c575b6fbeb1e33b69cf8357a2a7dbf6868b5f98cfb82b83243daccc0cf9" TOKEN_FILE="/tmp/aikido_endpoint_token.txt" # Colors for output @@ -111,10 +111,10 @@ main() { esac # 2. Download and verify checksum - PKG_FILE=$(mktemp /tmp/SafeChainUltimate.XXXXXX.pkg) + PKG_FILE=$(mktemp /tmp/AikidoEndpoint.XXXXXX.pkg) trap cleanup EXIT - info "Downloading SafeChain Ultimate..." + info "Downloading Aikido Endpoint Protection..." download "$INSTALL_URL" "$PKG_FILE" info "Verifying checksum..." @@ -124,10 +124,10 @@ main() { printf "%s" "$TOKEN" > "$TOKEN_FILE" # 4. Install the package - info "Installing SafeChain Ultimate..." + info "Installing Aikido Endpoint Protection..." installer -pkg "$PKG_FILE" -target / - info "SafeChain Ultimate installed successfully!" + info "Aikido Endpoint Protection installed successfully!" } main "$@" diff --git a/install-scripts/install-endpoint-windows.ps1 b/install-scripts/install-endpoint-windows.ps1 index f99d1ff..4407d83 100644 --- a/install-scripts/install-endpoint-windows.ps1 +++ b/install-scripts/install-endpoint-windows.ps1 @@ -1,4 +1,4 @@ -# Downloads and installs SafeChain Ultimate endpoint on Windows +# Downloads and installs Aikido Endpoint Protection on Windows # # Usage: iex "& { $(iwr '' -UseBasicParsing) } -token " @@ -7,8 +7,8 @@ param( ) # Configuration -$InstallUrl = "https://github.com/AikidoSec/safechain-internals/releases/download/v1.2.5/SafeChainUltimate.msi" -$DownloadSha256 = "c4d1be7bb2128473b8e955244dc186b5d3f091f668b43cdd3d810cff9d38193c" +$InstallUrl = "https://github.com/AikidoSec/safechain-internals/releases/download/v1.2.7/EndpointProtection.msi" +$DownloadSha256 = "7bad18d7df9e0654d2edd16a52aea34b0455c3c6d8fb407362d0a86a77cb7d4f" # Ensure TLS 1.2 is enabled for downloads [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 @@ -53,9 +53,9 @@ function Install-Endpoint { } # 2. Download the .msi - $msiFile = Join-Path $env:TEMP "SafeChainUltimate-$([System.Guid]::NewGuid().ToString('N')).msi" + $msiFile = Join-Path $env:TEMP "AikidoEndpoint-$([System.Guid]::NewGuid().ToString('N')).msi" - Write-Info "Downloading SafeChain Ultimate..." + Write-Info "Downloading Aikido Endpoint Protection..." try { $ProgressPreference = 'SilentlyContinue' Invoke-WebRequest -Uri $InstallUrl -OutFile $msiFile -UseBasicParsing @@ -75,13 +75,13 @@ function Install-Endpoint { Write-Info "Checksum verified successfully." # 3. Install the package with token passed as MSI property - Write-Info "Installing SafeChain Ultimate..." + Write-Info "Installing Aikido Endpoint Protection..." $process = Start-Process -FilePath "msiexec" -ArgumentList "/i", "`"$msiFile`"", "/qn", "/norestart", "AIKIDO_TOKEN=$token" -Wait -PassThru if ($process.ExitCode -ne 0) { Write-Error-Custom "MSI installer failed (exit code: $($process.ExitCode))." } - Write-Info "SafeChain Ultimate installed successfully!" + Write-Info "Aikido Endpoint Protection installed successfully!" } finally { # Cleanup diff --git a/install-scripts/uninstall-endpoint-mac.sh b/install-scripts/uninstall-endpoint-mac.sh old mode 100644 new mode 100755 index b1ba6e4..6da0f17 --- a/install-scripts/uninstall-endpoint-mac.sh +++ b/install-scripts/uninstall-endpoint-mac.sh @@ -1,13 +1,13 @@ #!/bin/sh -# Uninstalls SafeChain Ultimate endpoint on macOS +# Uninstalls Aikido Endpoint Protection on macOS # # Usage: curl -fsSL | sudo sh set -e # Exit on error # Configuration -UNINSTALL_SCRIPT="/Library/Application Support/AikidoSecurity/SafeChainUltimate/scripts/uninstall" +UNINSTALL_SCRIPT="/Library/Application Support/AikidoSecurity/EndpointProtection/scripts/uninstall" # Colors for output RED='\033[0;31m' @@ -38,13 +38,13 @@ main() { # Check if the uninstall script exists if [ ! -f "$UNINSTALL_SCRIPT" ]; then - error "SafeChain Ultimate does not appear to be installed (uninstall script not found)." + error "Aikido Endpoint Protection does not appear to be installed (uninstall script not found)." fi - info "Uninstalling SafeChain Ultimate..." + info "Uninstalling Aikido Endpoint Protection..." "$UNINSTALL_SCRIPT" - info "SafeChain Ultimate uninstalled successfully!" + info "Aikido Endpoint Protection uninstalled successfully!" } main "$@" diff --git a/install-scripts/uninstall-endpoint-windows.ps1 b/install-scripts/uninstall-endpoint-windows.ps1 index 5de5bfe..90741c7 100644 --- a/install-scripts/uninstall-endpoint-windows.ps1 +++ b/install-scripts/uninstall-endpoint-windows.ps1 @@ -1,9 +1,9 @@ -# Uninstalls SafeChain Ultimate endpoint on Windows +# Uninstalls Aikido Endpoint Protection endpoint on Windows # # Usage: iex (iwr '' -UseBasicParsing) # Configuration -$AppName = "SafeChain Ultimate" +$AppName = "Aikido Endpoint Protection" # Helper functions function Write-Info { @@ -32,22 +32,22 @@ function Uninstall-Endpoint { } # Find the installed product - Write-Info "Looking for SafeChain Ultimate installation..." + Write-Info "Looking for Aikido Endpoint Protection installation..." $app = Get-WmiObject -Class Win32_Product -Filter "Name='$AppName'" if (-not $app) { - Write-Error-Custom "SafeChain Ultimate does not appear to be installed." + Write-Error-Custom "Aikido Endpoint Protection does not appear to be installed." } $productCode = $app.IdentifyingNumber - Write-Info "Uninstalling SafeChain Ultimate..." + Write-Info "Uninstalling Aikido Endpoint Protection..." $process = Start-Process -FilePath "msiexec" -ArgumentList "/x", $productCode, "/qn", "/norestart" -Wait -PassThru if ($process.ExitCode -ne 0) { Write-Error-Custom "Uninstall failed (exit code: $($process.ExitCode))." } - Write-Info "SafeChain Ultimate uninstalled successfully!" + Write-Info "Aikido Endpoint Protection uninstalled successfully!" } # Run uninstallation diff --git a/packages/safe-chain/src/installation/downloadAgent.js b/packages/safe-chain/src/installation/downloadAgent.js deleted file mode 100644 index 297908a..0000000 --- a/packages/safe-chain/src/installation/downloadAgent.js +++ /dev/null @@ -1,125 +0,0 @@ -import { createWriteStream, createReadStream } from "fs"; -import { createHash } from "crypto"; -import { pipeline } from "stream/promises"; -import fetch from "make-fetch-happen"; - -const ULTIMATE_VERSION = "v1.0.0"; - -export const DOWNLOAD_URLS = { - win32: { - x64: { - url: `https://github.com/AikidoSec/safechain-internals/releases/download/${ULTIMATE_VERSION}/SafeChainUltimate-windows-amd64.msi`, - checksum: - "sha256:c6a36f9b8e55ab6b7e8742cbabc4469d85809237c0f5e6c21af20b36c416ee1d", - }, - arm64: { - url: `https://github.com/AikidoSec/safechain-internals/releases/download/${ULTIMATE_VERSION}/SafeChainUltimate-windows-arm64.msi`, - checksum: - "sha256:46acd1af6a9938ea194c8ee8b34ca9b47c8de22e088a0791f3c0751dd6239c90", - }, - }, - darwin: { - x64: { - url: `https://github.com/AikidoSec/safechain-internals/releases/download/${ULTIMATE_VERSION}/SafeChainUltimate-darwin-amd64.pkg`, - checksum: - "sha256:bb1829e8ca422e885baf37bef08dcbe7df7a30f248e2e89c4071564f7d4f3396", - }, - arm64: { - url: `https://github.com/AikidoSec/safechain-internals/releases/download/${ULTIMATE_VERSION}/SafeChainUltimate-darwin-arm64.pkg`, - checksum: - "sha256:7fe4a785709911cc366d8224b4c290677573b8c4833bd9054768299e55c5f0ed", - }, - }, -}; - -/** - * Builds the download URL for the SafeChain Agent installer. - * @param {string} fileName - */ -export function getAgentDownloadUrl(fileName) { - return `https://github.com/AikidoSec/safechain-internals/releases/download/${ULTIMATE_VERSION}/${fileName}`; -} - -/** - * Downloads a file from a URL to a local path. - * @param {string} url - * @param {string} destPath - */ -export async function downloadFile(url, destPath) { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`Download failed: ${response.statusText}`); - } - await pipeline(response.body, createWriteStream(destPath)); -} - -/** - * Returns the current agent version. - */ -export function getAgentVersion() { - return ULTIMATE_VERSION; -} - -/** - * Returns download info (url, checksum) for the current OS and architecture. - * @returns {{ url: string, checksum: string } | null} - */ -export function getDownloadInfoForCurrentPlatform() { - const platform = process.platform; - const arch = process.arch; - - if (!Object.hasOwn(DOWNLOAD_URLS, platform)) { - return null; - } - const platformUrls = - DOWNLOAD_URLS[/** @type {keyof typeof DOWNLOAD_URLS} */ (platform)]; - - if (!Object.hasOwn(platformUrls, arch)) { - return null; - } - - return platformUrls[/** @type {keyof typeof platformUrls} */ (arch)]; -} - -/** - * Verifies the checksum of a file. - * @param {string} filePath - * @param {string} expectedChecksum - Format: "algorithm:hash" (e.g., "sha256:abc123...") - * @returns {Promise} - */ -export async function verifyChecksum(filePath, expectedChecksum) { - const [algorithm, expected] = expectedChecksum.split(":"); - - const hash = createHash(algorithm); - - if (filePath.includes("..")) throw new Error("Invalid file path"); - const stream = createReadStream(filePath); - - for await (const chunk of stream) { - hash.update(chunk); - } - - const actual = hash.digest("hex"); - return actual === expected; -} - -/** - * Downloads the SafeChain agent for the current OS/arch and verifies its checksum. - * @param {string} fileName - Destination file path - * @returns {Promise} The file path if successful, null if no download URL for current platform - */ -export async function downloadAgentToFile(fileName) { - const info = getDownloadInfoForCurrentPlatform(); - if (!info) { - return null; - } - - await downloadFile(info.url, fileName); - - const isValid = await verifyChecksum(fileName, info.checksum); - if (!isValid) { - throw new Error("Checksum verification failed"); - } - - return fileName; -} diff --git a/packages/safe-chain/src/installation/downloadAgent.spec.js b/packages/safe-chain/src/installation/downloadAgent.spec.js deleted file mode 100644 index 44e53c0..0000000 --- a/packages/safe-chain/src/installation/downloadAgent.spec.js +++ /dev/null @@ -1,56 +0,0 @@ -import { describe, it, after } from "node:test"; -import assert from "node:assert"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { unlinkSync, writeFileSync } from "node:fs"; -import { createHash } from "node:crypto"; -import { - DOWNLOAD_URLS, - verifyChecksum, -} from "./downloadAgent.js"; - -describe("downloadAgent", () => { - const tempFiles = []; - - after(() => { - for (const file of tempFiles) { - try { - unlinkSync(file); - } catch { - // ignore cleanup errors - } - } - }); - - for (const [platform, architectures] of Object.entries(DOWNLOAD_URLS)) { - for (const [arch, { url, checksum }] of Object.entries(architectures)) { - it(`${platform}/${arch} has a valid download definition`, () => { - assert.match( - url, - /^https:\/\/github\.com\/AikidoSec\/safechain-internals\/releases\/download\/v\d+\.\d+\.\d+\/.+/, - ); - assert.match(checksum, /^sha256:[a-f0-9]{64}$/); - }); - } - } - - it("verifies checksum for a local file", async () => { - const destPath = join(tmpdir(), `safe-chain-test-${Date.now()}`); - tempFiles.push(destPath); - - writeFileSync(destPath, "safe-chain-test"); - - const expectedHash = createHash("sha256") - .update("safe-chain-test") - .digest("hex"); - - assert.equal( - await verifyChecksum(destPath, `sha256:${expectedHash}`), - true, - ); - assert.equal( - await verifyChecksum(destPath, `sha256:${"0".repeat(64)}`), - false, - ); - }); -}); diff --git a/packages/safe-chain/src/installation/installOnMacOS.js b/packages/safe-chain/src/installation/installOnMacOS.js deleted file mode 100644 index 22ce1a8..0000000 --- a/packages/safe-chain/src/installation/installOnMacOS.js +++ /dev/null @@ -1,155 +0,0 @@ -import { tmpdir } from "os"; -import { unlinkSync } from "fs"; -import { join } from "path"; -import { execSync, spawnSync } from "child_process"; -import { ui } from "../environment/userInteraction.js"; -import { printVerboseAndSafeSpawn } from "../utils/safeSpawn.js"; -import { downloadAgentToFile, getAgentVersion } from "./downloadAgent.js"; -import chalk from "chalk"; - -const MACOS_PKG_IDENTIFIER = "com.aikidosecurity.safechainultimate"; - -/** - * Checks if root privileges are available and displays error message if not. - * @param {string} command - The sudo command to show in the error message - * @returns {boolean} True if running as root, false otherwise. - */ -function requireRootPrivileges(command) { - if (isRunningAsRoot()) { - return true; - } - - ui.writeError("Root privileges required."); - ui.writeInformation("Please run this command with sudo:"); - ui.writeInformation(` ${command}`); - return false; -} - -function isRunningAsRoot() { - const rootUserUid = 0; - return process.getuid?.() === rootUserUid; -} - -export async function installOnMacOS() { - if (!requireRootPrivileges("sudo safe-chain ultimate")) { - return; - } - - const pkgPath = join(tmpdir(), `SafeChainUltimate-${Date.now()}.pkg`); - - ui.emptyLine(); - ui.writeInformation(`đŸ“Ĩ Downloading SafeChain Ultimate ${getAgentVersion()}`); - ui.writeVerbose(`Destination: ${pkgPath}`); - - const result = await downloadAgentToFile(pkgPath); - if (!result) { - ui.writeError("No download available for this platform/architecture."); - return; - } - - try { - ui.writeInformation("âš™ī¸ Installing SafeChain Ultimate..."); - await runPkgInstaller(pkgPath); - - ui.emptyLine(); - ui.writeInformation( - "✅ SafeChain Ultimate installed and started successfully!", - ); - ui.emptyLine(); - ui.writeInformation( - chalk.cyan("🔐 ") + - chalk.bold("ACTION REQUIRED: ") + - "macOS will show a popup to install our certificate.", - ); - ui.writeInformation( - " " + - chalk.bold("Please accept the certificate") + - " to complete the installation.", - ); - ui.emptyLine(); - } finally { - ui.writeVerbose(`Cleaning up temporary file: ${pkgPath}`); - cleanup(pkgPath); - } -} - -const MACOS_UNINSTALL_SCRIPT = - "/Library/Application\\ Support/AikidoSecurity/SafeChainUltimate/scripts/uninstall"; - -export async function uninstallOnMacOS() { - if (!requireRootPrivileges("sudo safe-chain ultimate uninstall")) { - return; - } - - ui.emptyLine(); - - if (!isPackageInstalled()) { - ui.writeInformation("SafeChain Ultimate is not installed."); - return; - } - - ui.writeInformation("đŸ—‘ī¸ Uninstalling SafeChain Ultimate..."); - ui.writeVerbose(`Running: ${MACOS_UNINSTALL_SCRIPT}`); - - const result = spawnSync(MACOS_UNINSTALL_SCRIPT, { - stdio: "inherit", - shell: true, - }); - - if (result.status !== 0) { - ui.writeError( - `Uninstall script failed (exit code: ${result.status}). Please try again or remove manually.`, - ); - return; - } - - ui.emptyLine(); - ui.writeInformation("✅ SafeChain Ultimate has been uninstalled."); - ui.emptyLine(); -} - -function isPackageInstalled() { - try { - const output = execSync(`pkgutil --pkg-info ${MACOS_PKG_IDENTIFIER}`, { - encoding: "utf8", - stdio: "pipe", - }); - return output.includes(MACOS_PKG_IDENTIFIER); - } catch { - return false; - } -} - -/** - * @param {string} pkgPath - */ -async function runPkgInstaller(pkgPath) { - // Uses installer to install the package (https://ss64.com/mac/installer.html) - // Options: - // -pkg (required): The package to be installed. - // -target (required): The target volume is specified with the -target parameter. - // --> "-target /" installs to the current boot volume. - - const result = await printVerboseAndSafeSpawn( - "installer", - ["-pkg", pkgPath, "-target", "/"], - { - stdio: "inherit", - }, - ); - - if (result.status !== 0) { - throw new Error(`PKG installer failed (exit code: ${result.status})`); - } -} - -/** - * @param {string} pkgPath - */ -function cleanup(pkgPath) { - try { - unlinkSync(pkgPath); - } catch { - ui.writeVerbose("Failed to clean up temporary installer file."); - } -} diff --git a/packages/safe-chain/src/installation/installOnWindows.js b/packages/safe-chain/src/installation/installOnWindows.js deleted file mode 100644 index 4cee911..0000000 --- a/packages/safe-chain/src/installation/installOnWindows.js +++ /dev/null @@ -1,203 +0,0 @@ -import { tmpdir } from "os"; -import { unlinkSync } from "fs"; -import { join } from "path"; -import { execSync } from "child_process"; -import { ui } from "../environment/userInteraction.js"; -import { printVerboseAndSafeSpawn, safeSpawn } from "../utils/safeSpawn.js"; -import { downloadAgentToFile, getAgentVersion } from "./downloadAgent.js"; - -const WINDOWS_SERVICE_NAME = "SafeChainUltimate"; -const WINDOWS_APP_NAME = "SafeChain Ultimate"; - -export async function uninstallOnWindows() { - if (!(await requireAdminPrivileges())) { - return; - } - - ui.emptyLine(); - - const productCode = getInstalledProductCode(); - if (!productCode) { - ui.writeInformation("SafeChain Ultimate is not installed."); - return; - } - - await stopServiceIfRunning(); - - ui.writeInformation("đŸ—‘ī¸ Uninstalling SafeChain Ultimate..."); - await uninstallByProductCode(productCode); - - ui.emptyLine(); - ui.writeInformation("✅ SafeChain Ultimate has been uninstalled."); - ui.emptyLine(); -} - -export async function installOnWindows() { - if (!(await requireAdminPrivileges())) { - return; - } - - const msiPath = join(tmpdir(), `SafeChainUltimate-${Date.now()}.msi`); - - ui.emptyLine(); - ui.writeInformation(`đŸ“Ĩ Downloading SafeChain Ultimate ${getAgentVersion()}`); - ui.writeVerbose(`Destination: ${msiPath}`); - - const result = await downloadAgentToFile(msiPath); - if (!result) { - ui.writeError("No download available for this platform/architecture."); - return; - } - - try { - ui.emptyLine(); - await stopServiceIfRunning(); - await uninstallIfInstalled(); - - ui.writeInformation("âš™ī¸ Installing SafeChain Ultimate..."); - await runMsiInstaller(msiPath); - - ui.emptyLine(); - ui.writeInformation( - "✅ SafeChain Ultimate installed and started successfully!", - ); - ui.emptyLine(); - } finally { - ui.writeVerbose(`Cleaning up temporary file: ${msiPath}`); - cleanup(msiPath); - } -} - -/** - * Checks if admin privileges are available and displays error message if not. - * @returns {Promise} True if running as admin, false otherwise. - */ -async function requireAdminPrivileges() { - if (await isRunningAsAdmin()) { - return true; - } - - ui.writeError("Administrator privileges required."); - ui.writeInformation( - "Please run this command in an elevated terminal (Run as Administrator).", - ); - return false; -} - -async function isRunningAsAdmin() { - // Uses Windows Security API to check if current process has admin privileges. - // Returns "True" or "False" as a string. - const result = await safeSpawn( - "powershell", - [ - "-Command", - "([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)", - ], - { stdio: "pipe" }, - ); - - return result.status === 0 && result.stdout.trim() === "True"; -} - -/** - * Returns the MSI product code for SafeChain Ultimate, or null if not installed. - * @returns {string | null} - */ -function getInstalledProductCode() { - // Query Win32_Product via WMI to find the installed SafeChain Agent. - // If found, outputs the product GUID (e.g., "{12345678-1234-...}") needed for msiexec uninstall. - ui.writeVerbose(`Finding product code with PowerShell`); - - let productCode; - try { - productCode = execSync( - `powershell -Command "$app = Get-WmiObject -Class Win32_Product -Filter \\"Name='${WINDOWS_APP_NAME}'\\"; if ($app) { Write-Output $app.IdentifyingNumber }"`, - { encoding: "utf8" }, - ).trim(); - } catch { - return null; - } - return productCode || null; -} - -/** - * @param {string} productCode - */ -async function uninstallByProductCode(productCode) { - ui.writeVerbose(`Found product code: ${productCode}`); - - // Use msiexec to run the msi installer quitely (https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/msiexec) - // Options: - // - /x: Uninstalls the package. - // - /qn: Specifies there's no UI during the installation process. - // - /norestart: Stops the device from restarting after the installation completes. - const uninstallResult = await printVerboseAndSafeSpawn( - "msiexec", - ["/x", productCode, "/qn", "/norestart"], - { stdio: "inherit" }, - ); - - if (uninstallResult.status !== 0) { - throw new Error(`Uninstall failed (exit code: ${uninstallResult.status})`); - } -} - -async function uninstallIfInstalled() { - const productCode = getInstalledProductCode(); - if (!productCode) { - ui.writeVerbose("No existing installation found (fresh install)."); - return; - } - - ui.writeInformation("đŸ—‘ī¸ Removing previous installation..."); - await uninstallByProductCode(productCode); -} - -/** - * @param {string} msiPath - */ -async function runMsiInstaller(msiPath) { - // Use msiexec to run the msi installer quitely (https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/msiexec) - // Options: - // - /i: Specifies normal installation - // - /qn: Specifies there's no UI during the installation process. - - const result = await printVerboseAndSafeSpawn( - "msiexec", - ["/i", msiPath, "/qn"], - { - stdio: "inherit", - }, - ); - - if (result.status !== 0) { - throw new Error(`MSI installer failed (exit code: ${result.status})`); - } -} - -async function stopServiceIfRunning() { - ui.writeInformation("âšī¸ Stopping running service..."); - - const result = await printVerboseAndSafeSpawn( - "net", - ["stop", WINDOWS_SERVICE_NAME], - { - stdio: "pipe", - }, - ); - - if (result.status !== 0) { - ui.writeVerbose("Service not running (will start after installation)."); - } -} - -/** - * @param {string} msiPath - */ -function cleanup(msiPath) { - try { - unlinkSync(msiPath); - } catch { - ui.writeVerbose("Failed to clean up temporary installer file."); - } -} diff --git a/packages/safe-chain/src/installation/installUltimate.js b/packages/safe-chain/src/installation/installUltimate.js deleted file mode 100644 index 257c953..0000000 --- a/packages/safe-chain/src/installation/installUltimate.js +++ /dev/null @@ -1,35 +0,0 @@ -import { platform } from "os"; -import { ui } from "../environment/userInteraction.js"; -import { initializeCliArguments } from "../config/cliArguments.js"; -import { installOnWindows, uninstallOnWindows } from "./installOnWindows.js"; -import { installOnMacOS, uninstallOnMacOS } from "./installOnMacOS.js"; - -export async function uninstallUltimate() { - initializeCliArguments(process.argv); - - const operatingSystem = platform(); - - if (operatingSystem === "win32") { - await uninstallOnWindows(); - } else if (operatingSystem === "darwin") { - await uninstallOnMacOS(); - } else { - ui.writeInformation( - `Uninstall is not yet supported on ${operatingSystem}.`, - ); - } -} - -export async function installUltimate() { - const operatingSystem = platform(); - - if (operatingSystem === "win32") { - await installOnWindows(); - } else if (operatingSystem === "darwin") { - await installOnMacOS(); - } else { - ui.writeInformation( - `${operatingSystem} is not supported yet by SafeChain's ultimate version.`, - ); - } -}