#!/usr/bin/env bash # ============================================================================= # Timmy node — fetch LNbits admin API key # # Run this after LNbits is up and your LND wallet is initialised. # Prints LNBITS_URL and LNBITS_API_KEY to paste into Replit secrets. # # Compatibility: # LNbits < 0.12 — auto-creates a wallet via superuser API # LNbits >= 0.12 — superuser API removed; walks you through the Admin UI # ============================================================================= set -euo pipefail LNBITS_LOCAL="http://127.0.0.1:5000" LNBITS_DATA_DIR="$HOME/.lnbits-data" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SECRETS_FILE="$SCRIPT_DIR/.node-secrets" GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m' info() { echo -e "${CYAN}[keys]${NC} $*"; } ok() { echo -e "${GREEN}[ok]${NC} $*"; } warn() { echo -e "${YELLOW}[warn]${NC} $*"; } die() { echo -e "${RED}[error]${NC} $*" >&2; exit 1; } # ─── Helpers ───────────────────────────────────────────────────────────────── # Return 0 (true) if $1 >= $2 (semver comparison, macOS/BSD-safe) # Uses python3 when available (already required for JSON parsing elsewhere), # otherwise falls back to pure-bash numeric major.minor.patch comparison. version_gte() { local v1="$1" v2="$2" if command -v python3 &>/dev/null; then python3 - "$v1" "$v2" <<'PYEOF' import sys def parse(v): parts = v.strip().split(".") return [int(x) for x in (parts + ["0","0","0"])[:3]] sys.exit(0 if parse(sys.argv[1]) >= parse(sys.argv[2]) else 1) PYEOF else # Pure-bash fallback: split on dots, compare numerically local IFS=. # shellcheck disable=SC2206 local a=($v1) b=($v2) for i in 0 1 2; do local av="${a[$i]:-0}" bv="${b[$i]:-0}" if (( av > bv )); then return 0; fi if (( av < bv )); then return 1; fi done return 0 # equal fi } # Print the export template the operator needs to paste into Replit Secrets print_export_template() { local api_key="${1:-}" echo "" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${GREEN} Paste these into Replit Secrets:${NC}" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" echo " export LNBITS_URL=\"http://bore.pub:\" ← bore port from expose.sh" echo " export LNBITS_API_KEY=\"${api_key}\"" echo "" } # ─── Step 1: Confirm LNbits is reachable ───────────────────────────────────── info "Checking LNbits at $LNBITS_LOCAL …" HEALTH_JSON="$(curl -sf --max-time 6 "$LNBITS_LOCAL/api/v1/health" 2>/dev/null || true)" if [[ -z "$HEALTH_JSON" ]]; then warn "LNbits is not reachable at $LNBITS_LOCAL (is it running?)." warn "Showing manual setup instructions — run this script again once LNbits is up." echo "" echo " Start LNbits, then re-run:" echo " bash $SCRIPT_DIR/get-lnbits-key.sh" echo "" print_export_template exit 0 fi # ─── Step 2: Detect LNbits version ─────────────────────────────────────────── LNBITS_VERSION="" if command -v python3 &>/dev/null; then LNBITS_VERSION="$(echo "$HEALTH_JSON" \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('server_version',''))" \ 2>/dev/null || true)" fi if [[ -z "$LNBITS_VERSION" ]]; then warn "Could not parse server_version from health endpoint — assuming modern LNbits (>= 0.12)." LNBITS_VERSION="0.12.0" fi info "LNbits version: ${LNBITS_VERSION}" # ─── Step 3: Version-branched key retrieval ─────────────────────────────────── if version_gte "$LNBITS_VERSION" "0.12.0"; then # ── LNbits >= 0.12 ───────────────────────────────────────────────────────── # The superuser wallet API (POST /api/v1/wallet with X-Api-Key: ) # was removed in 0.12. Use the Admin UI instead. echo "" warn "LNbits ${LNBITS_VERSION} — superuser API removed. Use the Admin UI:" echo "" echo " 1. Open the LNbits Admin UI in your browser:" echo " ${LNBITS_LOCAL}/admin" echo "" echo " 2. In the Admin UI sidebar, click Users → Create User" echo " Name: Timmy" echo " This creates a new user with a default wallet." echo "" echo " 3. Click on the Timmy user → open their wallet." echo "" echo " 4. In the wallet page, click the key icon (API Info)." echo " Copy the Admin key (not the Invoice key)." echo "" echo " 5. Paste the Admin key into Replit Secrets as LNBITS_API_KEY." echo "" print_export_template else # ── LNbits < 0.12 ────────────────────────────────────────────────────────── # Superuser API available — try to auto-create a Timmy wallet. info "LNbits ${LNBITS_VERSION} — attempting automatic wallet creation…" # Locate the super user ID (env file or secrets file) SUPER_USER="" if [[ -f "$LNBITS_DATA_DIR/.env" ]]; then SUPER_USER="$(grep LNBITS_SUPER_USER "$LNBITS_DATA_DIR/.env" \ | cut -d= -f2 | tr -d '"' || true)" fi [[ -f "$SECRETS_FILE" ]] && source "$SECRETS_FILE" SUPER_USER="${SUPER_USER:-${LNBITS_SUPER_USER:-}}" if [[ -z "$SUPER_USER" ]]; then # Last resort: grep the startup log for the first-run superuser line LOG_FILE="$HOME/Library/Logs/timmy-node/lnbits.log" if [[ -f "$LOG_FILE" ]]; then SUPER_USER="$(grep -oE "super user id: [a-f0-9]+" "$LOG_FILE" \ | tail -1 | awk '{print $4}' || true)" fi fi if [[ -z "$SUPER_USER" ]]; then warn "Could not locate LNbits super user ID automatically." echo "" echo " Visit ${LNBITS_LOCAL} and:" echo " 1. Create a wallet" echo " 2. Go to Wallet → API Info" echo " 3. Copy the Admin key" echo "" print_export_template exit 0 fi info "Super user ID: ${SUPER_USER}" # Create the Timmy wallet via superuser API WALLET_RESPONSE="$(curl -sf -X POST "$LNBITS_LOCAL/api/v1/wallet" \ -H "Content-Type: application/json" \ -H "X-Api-Key: $SUPER_USER" \ -d '{"name":"Timmy"}' 2>/dev/null || true)" if [[ -n "$WALLET_RESPONSE" ]]; then ADMIN_KEY="$(echo "$WALLET_RESPONSE" \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('adminkey',''))" \ 2>/dev/null || true)" INKEY="$(echo "$WALLET_RESPONSE" \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('inkey',''))" \ 2>/dev/null || true)" WALLET_ID="$(echo "$WALLET_RESPONSE" \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id',''))" \ 2>/dev/null || true)" if [[ -n "$ADMIN_KEY" ]]; then ok "Timmy wallet created (ID: ${WALLET_ID})" echo " Invoice key (read-only): ${INKEY}" # Append to secrets file so future runs can skip this step cat >> "$SECRETS_FILE" <