#!/usr/bin/env bash # The "harden" step — flip a node from open (setup) to paired (locked). Boards # boot LAN-open so a team can set up tokenless; once they're done, this locks the # node so only their group can reach it. # # Runs ON the board (loopback): pair-code minting + /admin/reload are localhost- # only, so this can't be a LAN-browser button. Trigger it over adb, from a board # shell, or wire it to a physical button — then hand the team the pair code it # prints (they enter it once in the dashboard's pairing screen). # # ./zeroclaw-lockdown.sh # on the board # adb -s shell '/home/arduino/zeroclaw-lockdown.sh' # from the host # # Env: # ZC_CONFIG config file (default /home/arduino/.zeroclaw/config.toml) # GATEWAY_PORT loopback gateway port (default 8080) # ZC_BIN zeroclaw binary (default /home/arduino/zeroclaw) set -uo pipefail CONFIG="${ZC_CONFIG:-/home/arduino/.zeroclaw/config.toml}" PORT="${GATEWAY_PORT:-8080}" ZC_BIN="${ZC_BIN:-/home/arduino/zeroclaw}" BASE="http://127.0.0.1:${PORT}" echo "==> locking down this node (require pairing)" # 1) Persist require_pairing=true. Prefer the running gateway's config API # (loopback → allowed even while pairing is off); fall back to editing the # toml directly if the endpoint isn't reachable. if ! curl -sf --max-time 5 -X PUT "${BASE}/api/config/prop?path=gateway.require_pairing" \ -H 'content-type: application/json' -d 'true' >/dev/null 2>&1; then echo " (config API unreachable — editing $CONFIG directly)" if grep -qE '^\s*require_pairing\s*=' "$CONFIG"; then sed -i 's/^\(\s*require_pairing\s*=\).*/\1 true/' "$CONFIG" else # insert under [gateway] sed -i '/^\[gateway\]/a require_pairing = true' "$CONFIG" fi fi # 2) Reload so the live PairingGuard picks up require_pairing=true. curl -sf --max-time 8 -X POST "${BASE}/admin/reload" >/dev/null 2>&1 || true # give the daemon a moment to come back paired for _ in $(seq 1 15); do curl -sf --max-time 2 "${BASE}/health" >/dev/null 2>&1 && break sleep 1 done # 3) Mint a fresh pair code (localhost-only). Try the admin endpoint, then the CLI. CODE="$(curl -sf --max-time 5 -X POST "${BASE}/admin/paircode/new" 2>/dev/null | grep -oE '[0-9]{6}' | head -1)" [ -n "$CODE" ] || CODE="$("$ZC_BIN" gateway get-paircode --new --port "$PORT" 2>/dev/null | grep -oE '[0-9]{6}' | head -1)" echo if [ -n "$CODE" ]; then echo " ┌───────────────────────────────────────────┐" echo " │ Node locked. Pairing code: ${CODE} │" echo " └───────────────────────────────────────────┘" echo " Enter it once in the dashboard's pairing screen (http://:${PORT}/pairing)." else echo " ! Node lockdown persisted, but couldn't mint a pair code automatically." echo " Run on the board: ${ZC_BIN} gateway get-paircode --new --port ${PORT}" fi