Files
Aether/apps/aether-tunnel/install.ps1

162 lines
6.7 KiB
PowerShell

$ErrorActionPreference = 'Stop'
$Repo = if ($env:AETHER_TUNNEL_RELEASE_REPO) { $env:AETHER_TUNNEL_RELEASE_REPO } else { 'fawney19/Aether' }
$ReleaseTag = $env:AETHER_TUNNEL_RELEASE_TAG
$InstallDir = $env:AETHER_TUNNEL_INSTALL_DIR
$ConfigPath = $env:AETHER_TUNNEL_CONFIG
function Say([string]$Message) { Write-Host "[Aether Tunnel] $Message" }
function Fail([string]$Message) { throw "[Aether Tunnel] $Message" }
function Prompt-IfEmpty([string]$Name, [string]$Value, [string]$Prompt) {
if (-not [string]::IsNullOrWhiteSpace($Value)) { return $Value }
$Read = Read-Host $Prompt
if ([string]::IsNullOrWhiteSpace($Read)) { Fail "$Name cannot be empty" }
return $Read
}
function ConvertTo-TomlQuotedString([string]$Value) {
return ($Value | ConvertTo-Json -Compress)
}
function Resolve-LatestTunnelTag {
if (-not [string]::IsNullOrWhiteSpace($ReleaseTag)) { return $ReleaseTag }
$Uri = "https://api.github.com/repos/$Repo/releases?per_page=100"
$Releases = Invoke-RestMethod -Uri $Uri -Headers @{ 'User-Agent' = 'aether-tunnel-installer' }
$TunnelReleases = @($Releases | Where-Object { -not $_.draft -and $_.tag_name -like 'tunnel-v*' } | Sort-Object published_at -Descending)
if ($TunnelReleases.Count -eq 0) { Fail "No tunnel-v* release found in $Repo" }
return $TunnelReleases[0].tag_name
}
function Test-IsAdministrator {
$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = [Security.Principal.WindowsPrincipal]::new($Identity)
return $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Initialize-Paths {
if ([string]::IsNullOrWhiteSpace($script:InstallDir)) {
if (Test-IsAdministrator) {
$script:InstallDir = Join-Path $env:ProgramFiles 'AetherTunnel'
} else {
$script:InstallDir = Join-Path $env:LOCALAPPDATA 'AetherTunnel'
}
}
if ([string]::IsNullOrWhiteSpace($script:ConfigPath)) {
if (Test-IsAdministrator) {
$script:ConfigPath = Join-Path $env:ProgramData 'AetherTunnel\aether-tunnel.toml'
} else {
$script:ConfigPath = Join-Path $env:APPDATA 'AetherTunnel\aether-tunnel.toml'
}
}
}
function Install-AetherTunnelBinary([string]$Tag, [string]$TempDir) {
if (-not [Environment]::Is64BitOperatingSystem) { Fail 'Windows release currently supports amd64 only' }
$Asset = 'aether-tunnel-windows-amd64.zip'
$Base = "https://github.com/$Repo/releases/download/$Tag"
$Archive = Join-Path $TempDir $Asset
$Sums = Join-Path $TempDir 'SHA256SUMS.txt'
Say "Downloading $Tag / $Asset"
Invoke-WebRequest -Uri "$Base/$Asset" -OutFile $Archive
try { Invoke-WebRequest -Uri "$Base/SHA256SUMS.txt" -OutFile $Sums } catch { $Sums = $null }
if ($Sums -and (Test-Path $Sums)) {
$ExpectedLine = Get-Content $Sums | Where-Object { $_ -match "\s$([regex]::Escape($Asset))$" } | Select-Object -First 1
if ($ExpectedLine) {
$Expected = ($ExpectedLine -split '\s+')[0]
$Actual = (Get-FileHash -Algorithm SHA256 $Archive).Hash.ToLowerInvariant()
if ($Actual -ne $Expected.ToLowerInvariant()) { Fail "SHA256 verification failed for $Asset" }
}
}
$ExtractDir = Join-Path $TempDir 'extract'
Expand-Archive -Path $Archive -DestinationPath $ExtractDir -Force
$Binary = Join-Path $ExtractDir 'aether-tunnel.exe'
if (-not (Test-Path $Binary)) { Fail 'aether-tunnel.exe not found in release asset' }
New-Item -ItemType Directory -Force -Path $script:InstallDir | Out-Null
Copy-Item $Binary (Join-Path $script:InstallDir 'aether-tunnel.exe') -Force
Say "Installed binary: $(Join-Path $script:InstallDir 'aether-tunnel.exe')"
}
function Test-LegacySingleServerConfig([string]$Path) {
if (-not (Test-Path $Path)) { return $false }
foreach ($Line in Get-Content $Path) {
if ($Line -match '^\s*\[') { return $false }
if ($Line -match '^\s*(aether_url|management_token)\s*=') { return $true }
}
return $false
}
function Test-ServerExists([string]$Path, [string]$QuotedUrl, [string]$QuotedName) {
if (-not (Test-Path $Path)) { return $false }
$FoundUrl = $false
$FoundName = $false
foreach ($Line in Get-Content $Path) {
if ($Line -match '^\s*\[\[servers\]\]\s*$') {
if ($FoundUrl -and $FoundName) { return $true }
$FoundUrl = $false
$FoundName = $false
}
if ($Line.Trim() -eq "aether_url = $QuotedUrl") { $FoundUrl = $true }
if ($Line.Trim() -eq "node_name = $QuotedName") { $FoundName = $true }
}
return ($FoundUrl -and $FoundName)
}
function Add-ServerConfig([string]$AetherUrl, [string]$ManagementToken, [string]$NodeName) {
$ConfigDir = Split-Path -Parent $script:ConfigPath
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
if (Test-LegacySingleServerConfig $script:ConfigPath) {
Fail "Existing config uses removed top-level aether_url/management_token. Run aether-tunnel setup to migrate to [[servers]] first: $script:ConfigPath"
}
$QuotedUrl = ConvertTo-TomlQuotedString $AetherUrl
$QuotedToken = ConvertTo-TomlQuotedString $ManagementToken
$QuotedName = ConvertTo-TomlQuotedString $NodeName
if (Test-ServerExists $script:ConfigPath $QuotedUrl $QuotedName) {
Say "Same aether_url + node_name already exists, skipping config append: $script:ConfigPath"
return
}
if (Test-Path $script:ConfigPath) {
Copy-Item $script:ConfigPath "$script:ConfigPath.bak.$(Get-Date -Format yyyyMMddHHmmss)" -Force
}
$Prefix = if ((Test-Path $script:ConfigPath) -and ((Get-Item $script:ConfigPath).Length -gt 0)) { "`n" } else { '' }
$Block = @(
"$Prefix# Added by Aether Tunnel one-click installer. Existing config is preserved.",
'[[servers]]',
"aether_url = $QuotedUrl",
"management_token = $QuotedToken",
"node_name = $QuotedName"
) -join "`n"
Add-Content -Path $script:ConfigPath -Value ($Block + "`n") -Encoding UTF8
Say "Appended [[servers]] to: $script:ConfigPath"
}
function Main {
Initialize-Paths
$AetherUrl = Prompt-IfEmpty 'AETHER_TUNNEL_AETHER_URL' $env:AETHER_TUNNEL_AETHER_URL 'Aether URL'
$ManagementToken = Prompt-IfEmpty 'AETHER_TUNNEL_MANAGEMENT_TOKEN' $env:AETHER_TUNNEL_MANAGEMENT_TOKEN 'Management token (ae_xxx)'
$NodeName = Prompt-IfEmpty 'AETHER_TUNNEL_NODE_NAME' $env:AETHER_TUNNEL_NODE_NAME 'Node name'
$TempDir = Join-Path ([IO.Path]::GetTempPath()) ("aether-tunnel-" + [Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
try {
$Tag = Resolve-LatestTunnelTag
Install-AetherTunnelBinary $Tag $TempDir
Add-ServerConfig $AetherUrl $ManagementToken $NodeName
} finally {
Remove-Item -Recurse -Force $TempDir -ErrorAction SilentlyContinue
}
Say 'Complete. Start or configure the node with:'
Say " & '$(Join-Path $script:InstallDir 'aether-tunnel.exe')' setup '$script:ConfigPath'"
}
Main