From d4d67295c600ec01e5bc5e45928c5e9cb39c1b19 Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Sun, 1 Nov 2026 10:51:17 -0500 Subject: [PATCH] Script to renew every host's gateway session over SSH --- README.md | 5 ++-- scripts/renew-hosts.sh | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100755 scripts/renew-hosts.sh diff --git a/README.md b/README.md index 007dae3..a9e7124 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,9 @@ docker exec -it wristcode-gateway wristcode device revoke The gateway exchanges the credential for a 30 day T3 session limited to reading and driving threads, so the long-lived token never leaves the gateway. T3 sessions cannot be refreshed. A week -before one expires, the watch gets a notification, and running `host add` again with a fresh -credential renews it. +before one expires, the watch gets a notification. [`scripts/renew-hosts.sh`](scripts/renew-hosts.sh) +renews every host in one go over SSH, passing each one-time credential straight to the gateway +without printing it. Edit its host list to match your machines. For local development, run `bun --watch src/main.ts` in `gateway/` with `WRISTCODE_DB` pointing at a scratch file. Without APNs settings, pushes are logged instead of sent. diff --git a/scripts/renew-hosts.sh b/scripts/renew-hosts.sh new file mode 100755 index 0000000..858bdc5 --- /dev/null +++ b/scripts/renew-hosts.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# Renews the gateway's T3 sessions, which last 30 days and cannot be refreshed. For each host it +# makes a one-time pairing credential on that host and hands it straight to `wristcode host add` +# on the gateway, so the credential is never printed. Run it from a machine that can SSH to every +# host by name. The watch warns a week before a session expires. +# +# scripts/renew-hosts.sh renew every host below +# scripts/renew-hosts.sh "Mac mini" renew one host by label +set -euo pipefail + +GATEWAY_SSH="${GATEWAY_SSH:-server.gib}" +GATEWAY_CONTAINER="${GATEWAY_CONTAINER:-wristcode-gateway}" + +# label | SSH host, or "local" for the machine running this script | public T3 URL +HOSTS=( + "Desktop|local|https://t3desktop.gbrown.org" + "Mac mini|mac.gib|https://t3mac.gbrown.org" + "server-gib|server.gib|https://t3sr.gbrown.org" + "LittleMan|junior.gib|https://t3jr.gbrown.org" +) + +# Prints a pairing credential. Runs on the T3 host. The CLI is not on PATH in non-login shells, +# so it looks where T3 Code installs it. +MINT=' +set -e +export T3CODE_HOME="${T3CODE_HOME:-$HOME/.t3}" +for candidate in "$(command -v t3 || true)" "$HOME/.t3/bin/t3" "$HOME/.local/bin/t3" $(ls -d "$HOME"/.t3/runtime/versions/*/t3 2>/dev/null | sort -V -r); do + if [ -n "$candidate" ] && [ -x "$candidate" ]; then t3="$candidate"; break; fi +done +[ -n "${t3:-}" ] || { echo "no t3 CLI found" >&2; exit 1; } +"$t3" auth pairing create --scope orchestration:read --scope orchestration:operate \ + --label "WristCode gateway" --ttl 10m --json | + sed -n "s/.*\"credential\": *\"\\([^\"]*\\)\".*/\\1/p" +' + +renew() { + local label="$1" ssh_host="$2" url="$3" credential + if [ "$ssh_host" = "local" ]; then + credential="$(bash -c "$MINT")" + else + credential="$(ssh -o BatchMode=yes "$ssh_host" "bash -s" <<<"$MINT")" + fi + if [ -z "$credential" ]; then + echo "$label: could not make a pairing credential" >&2 + return 1 + fi + # The credential travels on stdin, not on a command line other processes could read. + ssh -o BatchMode=yes "$GATEWAY_SSH" \ + "read -r credential && docker exec $GATEWAY_CONTAINER wristcode host add '$url' \"\$credential\" --label '$label'" \ + <<<"$credential" +} + +failed=0 +for entry in "${HOSTS[@]}"; do + IFS='|' read -r label ssh_host url <<<"$entry" + if [ $# -gt 0 ] && [ "$1" != "$label" ]; then continue; fi + renew "$label" "$ssh_host" "$url" || failed=1 +done + +ssh -o BatchMode=yes "$GATEWAY_SSH" "docker exec $GATEWAY_CONTAINER wristcode host list" | cut -f1,4 +exit "$failed"