The keeper's door asks for a key only root and the game's user can read, so another service on the host cannot re-seat anyone; the deploy makes the key once and the reseat script sends it from a file descriptor; and a seat link is taken out of the address bar with the browser's own call, since the page reads it before the router starts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MbtUPJ24P6vc6tE1x6RS3m
This commit is contained in:
Eric Wagoner
2026-10-13 18:28:28 -04:00
co-authored by Claude Opus 5.5
parent 8bbc41cc87
commit a2bdf7a825
5 changed files with 42 additions and 10 deletions
+6
View File
@@ -43,6 +43,12 @@ ssh "root@$HOST" '
install -m 755 /opt/hnefatafl/app/deploy/hnefatafl-rollup.sh /usr/local/bin/hnefatafl-rollup.sh
install -m 755 /opt/hnefatafl/app/deploy/hnefatafl-backup.sh /usr/local/bin/hnefatafl-backup.sh
install -m 755 /opt/hnefatafl/app/deploy/hnefatafl-reseat.sh /usr/local/bin/hnefatafl-reseat.sh
# The key to the keeper door: made once, readable by root (the reseat script) and the game user (the server) alone.
if [ ! -s /etc/hnefatafl/keeper.key ]; then
install -d -m 750 -o root -g hnefatafl /etc/hnefatafl
(umask 037; openssl rand -hex 32 > /etc/hnefatafl/keeper.key)
chown root:hnefatafl /etc/hnefatafl/keeper.key
fi
install -m 644 -D /opt/hnefatafl/app/deploy/traffic.py /usr/local/lib/hnefatafl/traffic.py
# On a host the hall shares, its hall-nightly.sh runs the rollup and backup
# of every game and checks in with Sentry once for all; a game on a box of
+6 -2
View File
@@ -8,8 +8,12 @@
set -euo pipefail
ROOM="${1:?usage: hnefatafl-reseat.sh ROOM [SEAT]}"
DOOR="http://127.0.0.1:8789/keeper/rooms/${ROOM^^}"
[ -s /etc/hnefatafl/keeper.key ] || { echo "No keeper's key at /etc/hnefatafl/keeper.key; a deploy makes it." >&2; exit 1; }
# The key goes as a header read from a file descriptor, never on a command line another user could see.
KEY="@/dev/fd/3"
exec 3< <(printf 'x-keeper-key: %s\n' "$(cat /etc/hnefatafl/keeper.key)")
if [ $# -lt 2 ]; then
curl -s "$DOOR" | python3 -c '
curl -s -H "$KEY" "$DOOR" | python3 -c '
import datetime, json, sys
r = json.load(sys.stdin)
if "error" in r: sys.exit(r["error"])
@@ -19,7 +23,7 @@ for s in r["seats"]:
print(" %-3s %-24s %s" % (s["id"], s["name"], when))
'
else
curl -s -X POST -H 'content-type: application/json' -d "{\"seat\":\"$2\"}" "$DOOR/reseat" | python3 -c '
curl -s -X POST -H "$KEY" -H 'content-type: application/json' -d "{\"seat\":\"$2\"}" "$DOOR/reseat" | python3 -c '
import json, sys
r = json.load(sys.stdin)
if "error" in r: sys.exit(r["error"])