# HireQuay wake daemon installer (Windows PowerShell 5.1+ / PowerShell 7). Served only from https://dl.hirequay.com. # # Safer than piping blind: read it first, then run it. # irm https://dl.hirequay.com/install-wake.ps1 -OutFile install-wake.ps1 # notepad install-wake.ps1 # read it # powershell -ExecutionPolicy Bypass -File .\install-wake.ps1 # Verify only (downloads to a temp folder, checks, installs nothing): set $env:HIREQUAY_WAKE_VERIFY_ONLY='1' first. # # What it does, and nothing else: # 1. checks for Node.js >= 20; # 2. downloads ONE pinned file (hirequay-wake.mjs v0.1.3) plus SHA256SUMS and SHA256SUMS.sig; # 3. stops unless the SHA-256 matches the value pinned below AND the Ed25519 signature over SHA256SUMS # verifies with the release key pinned below (checked with node, since .NET Framework has no Ed25519); # 4. installs the helper plus SHA256SUMS and SHA256SUMS.sig to %LOCALAPPDATA%\HireQuay\wake\bin with a hirequay-wake.cmd launcher (added to your user PATH); # 5. runs `hirequay-wake init` (pairs this PC with your HireQuay account; you approve it with your passkey); # 6. asks before registering a per-user logon start (Task Scheduler when available; otherwise a Startup-folder .cmd). # Uninstall: hirequay-wake uninstall --yes function Install-HireQuayWake { $ErrorActionPreference = 'Stop' $Version = '0.1.3' $Base = if ($env:HIREQUAY_WAKE_BASE) { $env:HIREQUAY_WAKE_BASE } else { 'https://dl.hirequay.com/wake' } # SHA-256 of release/0.1.3/hirequay-wake.mjs (same value in install-wake.sh). SHA256SUMS lists this installer too, # so change the pin only before signing (docs/ops/WAKE-RELEASE.md step 3). $Sha256 = '60b966e27a599a5cd27cfe737e659ebb5e7a36b54c3ce2b115c479455003fa41' # HireQuay release key (owner's offline Ed25519 key, D5b; public half only, base64url x). Same value in install-wake.sh, # hirequay-wake.ts and release-signing-key.pub.txt. The private key is never in this repo. $ReleaseKey = '1rdwT0w0pUasm82rmHWnZVaaqLbazffPcgEV2naa96U' $Dest = Join-Path $env:LOCALAPPDATA 'HireQuay\wake\bin' if ($Base -notmatch '^https://' -and $Base -notmatch '^http://127\.0\.0\.1:') { throw 'HIREQUAY_WAKE_BASE must be https://' } $node = Get-Command node -ErrorAction SilentlyContinue if (-not $node) { throw 'Node.js 20 or newer is required (https://nodejs.org).' } $major = [int]((& node -p 'process.versions.node').Split('.')[0]) if ($major -lt 20) { throw "Node.js 20 or newer is required (found $major)." } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $tmp = Join-Path ([IO.Path]::GetTempPath()) ("hqwake-" + [guid]::NewGuid()) New-Item -ItemType Directory -Path $tmp | Out-Null try { foreach ($f in 'hirequay-wake.mjs', 'SHA256SUMS', 'SHA256SUMS.sig') { Invoke-WebRequest -UseBasicParsing -Uri "$Base/v$Version/$f" -OutFile (Join-Path $tmp $f) } $got = (Get-FileHash -Algorithm SHA256 (Join-Path $tmp 'hirequay-wake.mjs')).Hash.ToLower() if ($got -ne $Sha256) { throw "Checksum mismatch ($got). Nothing was installed." } $env:HQ_DIR = $tmp; $env:HQ_SHA = $Sha256; $env:HQ_KEY = $ReleaseKey $js = @' const c=require("crypto"),fs=require("fs"),d=process.env.HQ_DIR; const sums=fs.readFileSync(d+"/SHA256SUMS"); if(!sums.toString().includes(process.env.HQ_SHA+" hirequay-wake.mjs")){console.error("SHA256SUMS does not list this file");process.exit(1)} const key=c.createPublicKey({key:{kty:"OKP",crv:"Ed25519",x:process.env.HQ_KEY},format:"jwk"}); const sig=Buffer.from(fs.readFileSync(d+"/SHA256SUMS.sig","utf8").trim(),"base64"); process.exit(c.verify(null,sums,key,sig)?0:1); '@ # Windows PowerShell 5.1 strips double quotes from native arguments, so `node -e $js` would break; run a file. $verifier = Join-Path $tmp 'verify.cjs' Set-Content -Path $verifier -Value $js -Encoding ASCII & node $verifier if ($LASTEXITCODE -ne 0) { throw 'Signature check failed. Nothing was installed.' } Write-Host "hirequay-wake: verified $Version (sha256 $Sha256)." if ($env:HIREQUAY_WAKE_VERIFY_ONLY -eq '1') { Write-Host 'hirequay-wake: verify only, nothing was installed.'; return } New-Item -ItemType Directory -Force -Path $Dest | Out-Null # Copy SUMS + sig beside the helper so runtime verifyRelease does not warn "unsigned development build". Copy-Item (Join-Path $tmp 'hirequay-wake.mjs') (Join-Path $Dest 'hirequay-wake.mjs') -Force Copy-Item (Join-Path $tmp 'SHA256SUMS') (Join-Path $Dest 'SHA256SUMS') -Force Copy-Item (Join-Path $tmp 'SHA256SUMS.sig') (Join-Path $Dest 'SHA256SUMS.sig') -Force Set-Content -Path (Join-Path $Dest 'hirequay-wake.cmd') -Encoding ASCII -Value "@node `"%~dp0hirequay-wake.mjs`" %*" $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') if (($userPath -split ';') -notcontains $Dest) { [Environment]::SetEnvironmentVariable('Path', ($userPath.TrimEnd(';') + ';' + $Dest), 'User') } $env:Path = "$env:Path;$Dest" Write-Host "hirequay-wake: installed $Dest\hirequay-wake.cmd" } finally { Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue Remove-Item Env:HQ_DIR, Env:HQ_SHA, Env:HQ_KEY -ErrorAction SilentlyContinue } if ($env:HIREQUAY_WAKE_SKIP_INIT -eq '1') { Write-Host 'hirequay-wake: skipping pairing.'; return } $initArgs = @('init'); if ($env:HIREQUAY_WAKE_AGENT) { $initArgs += @('--agent', $env:HIREQUAY_WAKE_AGENT) } & (Join-Path $Dest 'hirequay-wake.cmd') @initArgs $answer = Read-Host 'Start the wake daemon automatically when you sign in to Windows? [y/N]' # service install prefers Task Scheduler (COM, then schtasks). ONLOGON via schtasks.exe may need elevation; # if Task Scheduler is blocked the helper installs a per-user Startup-folder .cmd instead (no admin). if ($answer -match '^(y|yes)$') { & (Join-Path $Dest 'hirequay-wake.cmd') service install } else { Write-Host 'hirequay-wake: not installed as a task. Start it with: hirequay-wake run' } } # Everything runs from here, so a download cut off half-way cannot execute a partial script. Install-HireQuayWake