package handler const shellInstallScript = `#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: bash install.sh -s -t -b Options: -s Tunnel server address, for example 10.0.0.2:7000 -t One-time install token generated by the server -b Web console base URL, for example https://example.com:7500 EOF } require_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "missing required command: $1" >&2 exit 1 fi } detect_os() { case "$(uname -s)" in Linux) echo "linux" ;; Darwin) echo "darwin" ;; *) echo "unsupported operating system: $(uname -s)" >&2 exit 1 ;; esac } detect_arch() { case "$(uname -m)" in x86_64|amd64) echo "amd64" ;; aarch64|arm64) echo "arm64" ;; i386|i686) echo "386" ;; armv7l|armv6l|arm) echo "arm" ;; *) echo "unsupported architecture: $(uname -m)" >&2 exit 1 ;; esac } SERVER_ADDR="" INSTALL_TOKEN="" BASE_URL="" while getopts ":s:t:b:h" opt; do case "$opt" in s) SERVER_ADDR="$OPTARG" ;; t) INSTALL_TOKEN="$OPTARG" ;; b) BASE_URL="$OPTARG" ;; h) usage exit 0 ;; :) echo "option -$OPTARG requires a value" >&2 usage exit 1 ;; \?) echo "unknown option: -$OPTARG" >&2 usage exit 1 ;; esac done if [[ -z "$SERVER_ADDR" || -z "$INSTALL_TOKEN" || -z "$BASE_URL" ]]; then usage exit 1 fi require_cmd curl require_cmd tar require_cmd mktemp OS_NAME="$(detect_os)" ARCH_NAME="$(detect_arch)" BASE_URL="${BASE_URL%/}" INSTALL_ROOT="${HOME:-$(pwd)}/.gotunnel" BIN_DIR="$INSTALL_ROOT/bin" TARGET_BIN="$BIN_DIR/gotunnel-client" LOG_FILE="$INSTALL_ROOT/client.log" PID_FILE="$INSTALL_ROOT/client.pid" TMP_DIR="$(mktemp -d)" ARCHIVE_PATH="$TMP_DIR/gotunnel-client.tar.gz" DOWNLOAD_URL="$BASE_URL/install/client?os=$OS_NAME&arch=$ARCH_NAME" cleanup() { rm -rf "$TMP_DIR" } trap cleanup EXIT mkdir -p "$BIN_DIR" echo "Downloading GoTunnel client from $DOWNLOAD_URL" curl -fsSL -H "X-GoTunnel-Install-Token: $INSTALL_TOKEN" "$DOWNLOAD_URL" -o "$ARCHIVE_PATH" tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR" EXTRACTED_BIN="$(find "$TMP_DIR" -type f -name 'gotunnel-client*' ! -name '*.tar.gz' ! -name '*.zip' | head -n 1)" if [[ -z "$EXTRACTED_BIN" ]]; then echo "failed to find extracted client binary" >&2 exit 1 fi cp "$EXTRACTED_BIN" "$TARGET_BIN" chmod 0755 "$TARGET_BIN" if [[ -f "$PID_FILE" ]]; then OLD_PID="$(cat "$PID_FILE" 2>/dev/null || true)" if [[ -n "$OLD_PID" ]]; then kill "$OLD_PID" >/dev/null 2>&1 || true fi fi nohup "$TARGET_BIN" -s "$SERVER_ADDR" -t "$INSTALL_TOKEN" >>"$LOG_FILE" 2>&1 & NEW_PID=$! echo "$NEW_PID" >"$PID_FILE" echo "GoTunnel client installed to $TARGET_BIN" echo "Client started in background with PID $NEW_PID" echo "Logs: $LOG_FILE" ` const powerShellInstallScript = `function Get-GoTunnelArch { switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()) { 'x64' { return 'amd64' } 'arm64' { return 'arm64' } 'x86' { return '386' } default { throw "Unsupported architecture: $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)" } } } function Install-GoTunnel { param( [Parameter(Mandatory = $true)][string]$Server, [Parameter(Mandatory = $true)][string]$Token, [Parameter(Mandatory = $true)][string]$BaseUrl ) $BaseUrl = $BaseUrl.TrimEnd('/') $Arch = Get-GoTunnelArch $InstallRoot = Join-Path $env:LOCALAPPDATA 'GoTunnel' $ExtractDir = Join-Path $InstallRoot 'extract' $ArchivePath = Join-Path $InstallRoot 'gotunnel-client.zip' $TargetPath = Join-Path $InstallRoot 'gotunnel-client.exe' $DownloadUrl = "$BaseUrl/install/client?os=windows&arch=$Arch" New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null Write-Host "Downloading GoTunnel client from $DownloadUrl" $Headers = @{ 'X-GoTunnel-Install-Token' = $Token } Invoke-WebRequest -Uri $DownloadUrl -Headers $Headers -OutFile $ArchivePath -MaximumRedirection 5 if (Test-Path $ExtractDir) { Remove-Item -Path $ExtractDir -Recurse -Force } Expand-Archive -Path $ArchivePath -DestinationPath $ExtractDir -Force $Binary = Get-ChildItem -Path $ExtractDir -Recurse -File | Where-Object { $_.Name -eq 'gotunnel-client.exe' } | Select-Object -First 1 if (-not $Binary) { throw 'Failed to find extracted client binary.' } Copy-Item -Path $Binary.FullName -Destination $TargetPath -Force Get-Process | Where-Object { $_.Path -eq $TargetPath } | Stop-Process -Force -ErrorAction SilentlyContinue Start-Process -FilePath $TargetPath -ArgumentList @('-s', $Server, '-t', $Token) -WindowStyle Hidden Write-Host "GoTunnel client installed to $TargetPath" Write-Host 'Client started in background.' } `