#!/bin/sh # HireQuay wake daemon installer (macOS / Linux). Served only from https://dl.hirequay.com. # # Safer than piping blind: read it first, then run it. # curl -fsSLo install-wake.sh https://dl.hirequay.com/install-wake.sh # less install-wake.sh # read it # sh install-wake.sh # Verify only (downloads to a temp folder, checks, installs nothing): HIREQUAY_WAKE_VERIFY_ONLY=1 sh install-wake.sh # # 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. refuses to continue unless the SHA-256 matches the value pinned below AND the Ed25519 signature # over SHA256SUMS verifies with the release key pinned below; # 4. puts the helper plus SHA256SUMS and SHA256SUMS.sig in ~/.local/share/hirequay/wake/bin and a `hirequay-wake` launcher in ~/.local/bin; # 5. runs `hirequay-wake init` (pairs this computer with your HireQuay account; you approve it with your passkey); # 6. asks before registering a per-user service (systemd --user or launchd). Never uses sudo. # Uninstall: hirequay-wake uninstall --yes set -eu main() { VERSION="0.1.3" BASE="${HIREQUAY_WAKE_BASE:-https://dl.hirequay.com/wake}" # Pinned at release time. A changed file on the server fails here, even if HTTPS is fine. # SHA-256 of release/0.1.3/hirequay-wake.mjs (same value in install-wake.ps1). 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.ps1, # hirequay-wake.ts and release-signing-key.pub.txt. The private key is never in this repo. RELEASE_KEY="1rdwT0w0pUasm82rmHWnZVaaqLbazffPcgEV2naa96U" DEST="${XDG_DATA_HOME:-$HOME/.local/share}/hirequay/wake/bin" LINK="$HOME/.local/bin/hirequay-wake" command -v node >/dev/null 2>&1 || fail "Node.js 20 or newer is required (https://nodejs.org)." node -e 'process.exit(Number(process.versions.node.split(".")[0])>=20?0:1)' || fail "Node.js 20 or newer is required." command -v curl >/dev/null 2>&1 || fail "curl is required." case "$BASE" in https://*) PROTO='=https' ;; http://127.0.0.1:*) PROTO='=http' ;; # local testing only *) fail "HIREQUAY_WAKE_BASE must be https://" ;; esac TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT INT TERM for f in hirequay-wake.mjs SHA256SUMS SHA256SUMS.sig; do curl -fsSL --proto "$PROTO" --tlsv1.2 -o "$TMP/$f" "$BASE/v$VERSION/$f" || fail "download failed: $f" done # Verify with node so no extra tools are needed (sha256sum/shasum differ between systems). HQ_DIR="$TMP" HQ_SHA="$SHA256" HQ_KEY="$RELEASE_KEY" node -e ' const c=require("crypto"),fs=require("fs"),d=process.env.HQ_DIR; const file=fs.readFileSync(d+"/hirequay-wake.mjs"), sums=fs.readFileSync(d+"/SHA256SUMS"); const got=c.createHash("sha256").update(file).digest("hex"); if(got!==process.env.HQ_SHA){console.error("checksum mismatch: "+got);process.exit(1)} if(!sums.toString().includes(got+" 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"); if(!c.verify(null,sums,key,sig)){console.error("signature check failed");process.exit(1)} ' || fail "verification failed; nothing was installed." say "Verified hirequay-wake $VERSION (sha256 $SHA256)." if [ "${HIREQUAY_WAKE_VERIFY_ONLY:-0}" = "1" ]; then say "Verify only, nothing was installed."; return 0; fi mkdir -p "$DEST" "$(dirname "$LINK")" # Copy SUMS + sig beside the helper so runtime verifyRelease does not warn "unsigned development build". install -m 0644 "$TMP/hirequay-wake.mjs" "$DEST/hirequay-wake.mjs" install -m 0644 "$TMP/SHA256SUMS" "$DEST/SHA256SUMS" install -m 0644 "$TMP/SHA256SUMS.sig" "$DEST/SHA256SUMS.sig" printf '#!/bin/sh\nexec node "%s/hirequay-wake.mjs" "$@"\n' "$DEST" > "$LINK" chmod 0755 "$LINK" say "Installed $LINK" if [ "${HIREQUAY_WAKE_SKIP_INIT:-0}" = "1" ]; then say "Skipping pairing (HIREQUAY_WAKE_SKIP_INIT=1)."; return 0; fi "$LINK" init ${HIREQUAY_WAKE_AGENT:+--agent "$HIREQUAY_WAKE_AGENT"} &2; exit 1; } # Everything runs from here, so a download cut off half-way cannot execute a partial script. main "$@"