The script unconditionally wrote VITE_RELAY_URL + VITE_LNBITS_SERVER_PUBKEY (and hard-exited if it couldn't scrape the pubkey), env-pinning every provisioned machine and defeating the seed — the same bug as the activation default. Make it seed-first: with a SPIRE_SEED, relay + pubkey come from the seed and are written only when the operator explicitly passes RELAY_URL / LNBITS_SERVER_PUBKEY as a deliberate pin. The no-seed dev-nsec path still scrapes/defaults them. Also drops the unused VITE_LNBITS_HTTP_URL line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
6.4 KiB
Bash
Executable file
151 lines
6.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Provision a running bitSpire ATM (live USB, QEMU VM, or installed Sintra)
|
|
# with LNbits nostr-transport credentials. The ATM speaks to LNbits over
|
|
# kind-21000 NIP-44 v2 events on a relay — there is no out-of-band token,
|
|
# the ATM's nostr private key IS the credential. # pragma: allowlist secret
|
|
#
|
|
# The primary input is SPIRE_SEED — the pairing seed carries the relay, the
|
|
# LNbits server pubkey AND the signing identity, so a seed-provisioned machine
|
|
# needs nothing else (aiolabs/bitspire#70).
|
|
#
|
|
# Environment variables:
|
|
# SPIRE_SEED RECOMMENDED. The spire pairing seed
|
|
# (`spire-seed:v1:<base64url>`) minted by spirekeeper.
|
|
# Carries relay + LNbits server pubkey + the production
|
|
# identity under the NIP-46 bunker (aiolabs/bitspire#52 / #70).
|
|
# RELAY_URL OPTIONAL override — pins VITE_RELAY_URL and WINS over the
|
|
# seed's relay (env-first precedence). Leave unset to let the
|
|
# seed drive it. Required only on the no-seed dev path
|
|
# (default there: ws://$HOST_IP:5001/nostrrelay/test).
|
|
# LNBITS_SERVER_PUBKEY OPTIONAL override (hex). Leave unset with a seed. On the
|
|
# no-seed dev path it's scraped from
|
|
# `docker logs lnbits | grep 'nostr_transport pubkey'`.
|
|
# ATM_PRIVATE_KEY DEV-ONLY 32-byte hex nsec fallback, used only when
|
|
# SPIRE_SEED is unset (no bunker). Generated if unset
|
|
# AND no SPIRE_SEED is provided.
|
|
#
|
|
# Usage:
|
|
# bash provision-atm.sh # defaults: SSH to localhost:2222 (QEMU)
|
|
# bash provision-atm.sh 192.168.1.50 # SSH to a real ATM on the LAN
|
|
# bash provision-atm.sh 192.168.1.50 22 # custom SSH port
|
|
set -euo pipefail
|
|
|
|
ATM_HOST="${1:-localhost}"
|
|
ATM_SSH_PORT="${2:-2222}"
|
|
ATM_USER="bitspire"
|
|
|
|
# Machine model + fiat. Model is operator-set; fiat defaults per-model to
|
|
# match the flake's fiatCodeForModel table (sintra=EUR, douro/tejo=GTQ,
|
|
# batm3=USD). Operators can override either via env var.
|
|
MODEL="${MODEL:-sintra}"
|
|
case "${FIAT_CODE:-}" in
|
|
"")
|
|
case "$MODEL" in
|
|
sintra) FIAT_CODE=EUR ;;
|
|
douro|tejo) FIAT_CODE=GTQ ;;
|
|
batm3) FIAT_CODE=USD ;;
|
|
*) FIAT_CODE=USD ;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
echo "=== Provisioning bitSpire ATM at $ATM_HOST:$ATM_SSH_PORT ==="
|
|
|
|
# Step 1: Discover the host IP as seen from the ATM.
|
|
# QEMU user-mode networking puts the host at 10.0.2.2; on real LAN ATMs
|
|
# use the dev machine's outbound LAN address.
|
|
if [ "$ATM_HOST" = "localhost" ]; then
|
|
HOST_IP="10.0.2.2"
|
|
echo ""
|
|
echo "--- QEMU detected: using $HOST_IP as host gateway ---"
|
|
else
|
|
HOST_IP=$(ip -4 route get 1 | awk '{print $7; exit}')
|
|
echo ""
|
|
echo "--- LAN ATM: using $HOST_IP as dev machine address ---"
|
|
fi
|
|
|
|
# Steps 2-4: transport config (relay + LNbits server pubkey) + signing identity.
|
|
#
|
|
# Under aiolabs/bitspire#70 the relay + server pubkey come from the pairing SEED,
|
|
# so a seed-provisioned machine needs NEITHER in .env. We only pin them when the
|
|
# operator EXPLICITLY passes RELAY_URL / LNBITS_SERVER_PUBKEY (a deliberate
|
|
# override that WINS over the seed via env-first precedence), or when there is no
|
|
# seed (the dev-nsec fallback has nothing else to supply them, so we scrape/default).
|
|
TRANSPORT_LINES=""
|
|
|
|
if [ -n "${SPIRE_SEED:-}" ]; then
|
|
case "$SPIRE_SEED" in
|
|
spire-seed:v1:*) : ;;
|
|
*) echo "ERROR: SPIRE_SEED must start with 'spire-seed:v1:'"; exit 1 ;;
|
|
esac
|
|
echo ""
|
|
echo "--- Spire pairing seed: relay + LNbits pubkey come from the seed ---"
|
|
if [ -n "${RELAY_URL:-}" ]; then
|
|
echo " (pinning VITE_RELAY_URL=$RELAY_URL — overrides the seed's relay)"
|
|
TRANSPORT_LINES="VITE_RELAY_URL=$RELAY_URL"
|
|
fi
|
|
if [ -n "${LNBITS_SERVER_PUBKEY:-}" ]; then
|
|
TRANSPORT_LINES="${TRANSPORT_LINES:+$TRANSPORT_LINES
|
|
}VITE_LNBITS_SERVER_PUBKEY=$LNBITS_SERVER_PUBKEY"
|
|
fi
|
|
IDENTITY_LINES="# Spire pairing seed — bunker-backed identity (aiolabs/bitspire#52)
|
|
VITE_SPIRE_SEED=$SPIRE_SEED"
|
|
else
|
|
# No seed → DEV-ONLY nsec fallback. Nothing else supplies the relay + pubkey,
|
|
# so scrape/default them.
|
|
if [ -z "${LNBITS_SERVER_PUBKEY:-}" ]; then
|
|
echo ""
|
|
echo "--- No seed: extracting LNbits nostr-transport pubkey from docker logs ---"
|
|
LNBITS_SERVER_PUBKEY=$(docker logs lnbits 2>&1 \
|
|
| grep -oP 'nostr_transport pubkey:?\s*\K[a-f0-9]{64}' \
|
|
| tail -1 || true)
|
|
if [ -z "$LNBITS_SERVER_PUBKEY" ]; then
|
|
echo "ERROR: no SPIRE_SEED, and could not extract the LNbits pubkey."
|
|
echo "Provide a SPIRE_SEED (recommended — the seed carries relay + pubkey),"
|
|
echo "or set LNBITS_SERVER_PUBKEY explicitly."
|
|
exit 1
|
|
fi
|
|
fi
|
|
RELAY_URL="${RELAY_URL:-ws://$HOST_IP:5001/nostrrelay/test}"
|
|
TRANSPORT_LINES="VITE_RELAY_URL=$RELAY_URL
|
|
VITE_LNBITS_SERVER_PUBKEY=$LNBITS_SERVER_PUBKEY"
|
|
if [ -z "${ATM_PRIVATE_KEY:-}" ]; then
|
|
ATM_PRIVATE_KEY=$(openssl rand -hex 32)
|
|
echo ""
|
|
echo "--- No SPIRE_SEED; generated a DEV-ONLY ATM_PRIVATE_KEY (no bunker) ---"
|
|
fi
|
|
IDENTITY_LINES="# DEV-ONLY local nsec (no bunker pairing) # pragma: allowlist secret
|
|
VITE_ATM_PRIVATE_KEY=$ATM_PRIVATE_KEY"
|
|
fi
|
|
|
|
# Step 6: Write .env to the ATM via SSH.
|
|
echo ""
|
|
echo "--- Step 2: Writing .env to ATM ---"
|
|
ENV_CONTENT="# bitSpire Configuration
|
|
# Auto-generated by provision-atm.sh on $(date -Iseconds)
|
|
|
|
# LNbits nostr-transport. Relay + server pubkey come from the pairing seed
|
|
# (aiolabs/bitspire#70); present below only as an explicit override or the
|
|
# no-seed dev fallback.
|
|
$TRANSPORT_LINES
|
|
|
|
$IDENTITY_LINES
|
|
|
|
# Machine configuration
|
|
VITE_LAMASSU_MACHINE_MODEL=$MODEL
|
|
VITE_LAMASSU_FIAT_CODE=$FIAT_CODE
|
|
|
|
# Force production mode
|
|
ELECTRON_FORCE_PROD=1
|
|
DISPLAY=:0"
|
|
|
|
ssh -o StrictHostKeyChecking=no -p "$ATM_SSH_PORT" "$ATM_USER@$ATM_HOST" \
|
|
"echo '$ENV_CONTENT' | sudo tee /var/lib/bitspire/.env > /dev/null && sudo systemctl restart bitspire"
|
|
|
|
echo ""
|
|
echo "=== ATM provisioned successfully ==="
|
|
echo ""
|
|
echo "Credentials written to /var/lib/bitspire/.env"
|
|
echo "ATM service restarted. Relay: ${RELAY_URL:-from the pairing seed}."
|
|
echo ""
|
|
echo "To check status: ssh -p $ATM_SSH_PORT $ATM_USER@$ATM_HOST 'sudo journalctl -u bitspire -f'"
|