#!/usr/bin/env bash # test-nip07.sh — Validate NIP-07 Nostr signing infrastructure # # Tests server-side components of NIP-07 signing. # Browser-based tests (window.nostr in DevTools) must be done manually. # # Usage: ./scripts/test-nip07.sh [target-ip] set -uo pipefail TARGET="${1:-192.168.1.228}" SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" SSH="ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=10 archipelago@$TARGET" PASS=0 FAIL=0 check() { local name="$1" local ok="$2" if [ "$ok" = "true" ]; then echo " ✅ $name" ((PASS++)) else echo " ❌ $name" ((FAIL++)) fi } # Extract JSON field using python3 (runs locally) json_get() { python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',{}); print(r.get('$1','') if isinstance(r,dict) else '')" 2>/dev/null } echo "🔑 NIP-07 Nostr Signing Test — $TARGET" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # Login and get CSRF token echo "" echo "Authenticating..." $SSH "curl -s -c /tmp/cookiejar http://localhost:5678/rpc/v1 -H 'Content-Type: application/json' -d '{\"method\":\"auth.login\",\"params\":{\"password\":\"password123\"}}'" >/dev/null 2>&1 CSRF=$($SSH "grep csrf_token /tmp/cookiejar 2>/dev/null | awk '{print \$NF}'" 2>/dev/null) echo " CSRF: ${CSRF:0:16}..." rpc() { local method="$1" local params="${2:-}" local body if [ -n "$params" ]; then body="{\"method\":\"$method\",\"params\":$params}" else body="{\"method\":\"$method\"}" fi $SSH "curl -s -b /tmp/cookiejar -H 'Content-Type: application/json' -H 'X-CSRF-Token: $CSRF' http://localhost:5678/rpc/v1 -d '$body'" 2>/dev/null } # 1. nostr-provider.js exists on server echo "" echo "1. nostr-provider.js served by nginx" JS_EXISTS=$($SSH "curl -s -o /dev/null -w '%{http_code}' http://localhost/nostr-provider.js" 2>/dev/null) check "nostr-provider.js returns 200" "$([ "$JS_EXISTS" = "200" ] && echo true || echo false)" # 2. nostr-provider.js injected into iframe app echo "" echo "2. Script injection via sub_filter" INJECT_COUNT=$($SSH "curl -s http://localhost/app/mempool/ 2>/dev/null | grep -c 'nostr-provider.js'" 2>/dev/null) check "Injected into /app/mempool/" "$([ "$INJECT_COUNT" -ge 1 ] && echo true || echo false)" # 3. node.nostr-pubkey returns valid pubkey echo "" echo "3. Node Nostr pubkey" PUBKEY_RESP=$(rpc "node.nostr-pubkey") NODE_PK=$(echo "$PUBKEY_RESP" | json_get "nostr_pubkey") check "node.nostr-pubkey returns hex pubkey (${#NODE_PK} chars)" "$([ ${#NODE_PK} -eq 64 ] && echo true || echo false)" NODE_NPUB=$(echo "$PUBKEY_RESP" | json_get "nostr_npub") check "npub format valid" "$(echo "$NODE_NPUB" | grep -q '^npub1' && echo true || echo false)" # 4. node.nostr-sign returns signed event with matching pubkey echo "" echo "4. Event signing" CREATED_AT=$(date +%s) SIGN_RESP=$(rpc "node.nostr-sign" "{\"event\":{\"kind\":1,\"content\":\"NIP-07 automated test\",\"created_at\":$CREATED_AT,\"tags\":[]}}") SIGN_PK=$(echo "$SIGN_RESP" | json_get "pubkey") SIGN_SIG=$(echo "$SIGN_RESP" | json_get "sig") SIGN_ID=$(echo "$SIGN_RESP" | json_get "id") check "Signed event has pubkey (${#SIGN_PK} chars)" "$([ ${#SIGN_PK} -eq 64 ] && echo true || echo false)" check "Signed event has signature (${#SIGN_SIG} chars)" "$([ ${#SIGN_SIG} -gt 60 ] && echo true || echo false)" check "Signed event has id hash (${#SIGN_ID} chars)" "$([ ${#SIGN_ID} -eq 64 ] && echo true || echo false)" check "Signing pubkey matches node pubkey" "$([ "$SIGN_PK" = "$NODE_PK" ] && echo true || echo false)" # 5. Signed event content matches input echo "" echo "5. Event content integrity" SIGN_CONTENT=$(echo "$SIGN_RESP" | json_get "content") SIGN_KIND=$(echo "$SIGN_RESP" | json_get "kind") check "Content preserved" "$([ "$SIGN_CONTENT" = "NIP-07 automated test" ] && echo true || echo false)" check "Kind preserved" "$([ "$SIGN_KIND" = "1" ] && echo true || echo false)" # 6. NIP-04/NIP-44 encrypt/decrypt endpoints exist echo "" echo "6. NIP-04 encrypt/decrypt" ENC_RESP=$(rpc "identity.nostr-encrypt-nip04" "{\"pubkey\":\"$NODE_PK\",\"plaintext\":\"hello\"}") ENC_ERR=$(echo "$ENC_RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); e=d.get('error'); print(e.get('message','') if e else 'none')" 2>/dev/null) check "NIP-04 encrypt endpoint exists" "$(echo "$ENC_ERR" | grep -qv 'Unknown method' && echo true || echo false)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Results: $PASS passed, $FAIL failed" echo "" echo "📝 Manual browser test steps:" echo " 1. Open http://$TARGET/dashboard/apps" echo " 2. Launch an iframe app (e.g., Mempool)" echo " 3. Open DevTools console (F12)" echo " 4. Run: window.nostr" echo " → Should return object with getPublicKey, signEvent" echo " 5. Run: await window.nostr.getPublicKey()" echo " → Should return: $NODE_PK" echo " 6. Run: await window.nostr.signEvent({kind:1,content:'test',created_at:Math.floor(Date.now()/1000),tags:[]})" echo " → Consent modal should appear in parent frame" echo " → After approval, should return signed event with sig field" [ $FAIL -eq 0 ] && exit 0 || exit 1