feat: Add Nostr identity and trust tier tests (#44)
Some checks failed
CI / Typecheck & Lint (pull_request) Failing after 1s
Some checks failed
CI / Typecheck & Lint (pull_request) Failing after 1s
This commit is contained in:
21
scripts/gen_nostr_event.js
Normal file
21
scripts/gen_nostr_event.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
const { generatePrivateKey, getPublicKey, finalizeEvent } = require('nostr-tools');
|
||||||
|
|
||||||
|
const privateKey = generatePrivateKey();
|
||||||
|
const publicKey = getPublicKey(privateKey);
|
||||||
|
|
||||||
|
const nonce = process.argv[2]; // Nonce from challenge endpoint
|
||||||
|
|
||||||
|
if (!nonce) {
|
||||||
|
console.error("Usage: node gen_nostr_event.js <nonce>");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = finalizeEvent({
|
||||||
|
kind: 27235,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
tags: [['challenge', nonce]],
|
||||||
|
content: "NIP-27235 challenge response",
|
||||||
|
}, privateKey);
|
||||||
|
|
||||||
|
console.log(JSON.stringify(event));
|
||||||
150
timmy_test.sh
150
timmy_test.sh
@@ -422,6 +422,156 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Tests 17-23 — Nostr Identity & Trust Tiers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
sep "Tests 17-23 — Nostr Identity & Trust Tiers"
|
||||||
|
|
||||||
|
# Initialize Nostr keys and other variables
|
||||||
|
NOSTR_PRIV_KEY=$(node -e "const { generatePrivateKey } = require('nostr-tools'); console.log(generatePrivateKey());")
|
||||||
|
NOSTR_PUB_KEY=$(node -e "const { getPublicKey } = require('nostr-tools'); console.log(getPublicKey('$NOSTR_PRIV_KEY'));")
|
||||||
|
CHALLENGE_NONCE=""
|
||||||
|
NOSTR_TOKEN=""
|
||||||
|
IDENTITY_PUBKEY=""
|
||||||
|
|
||||||
|
# Test 17 — POST /api/identity/challenge
|
||||||
|
sep "Test 17 — POST /api/identity/challenge"
|
||||||
|
T17_RES=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/identity/challenge")
|
||||||
|
T17_BODY=$(echo "$T17_RES" | sed '$d')
|
||||||
|
T17_CODE=$(echo "$T17_RES" | tail -n1)
|
||||||
|
CHALLENGE_NONCE=$(jq_field "$T17_BODY" '.nonce')
|
||||||
|
EXPIRES_AT=$(jq_field "$T17_BODY" '.expiresAt')
|
||||||
|
|
||||||
|
if [[ "$T17_CODE" == "200" && -n "$CHALLENGE_NONCE" && ${#CHALLENGE_NONCE} == 32 && -n "$EXPIRES_AT" ]]; then
|
||||||
|
note PASS "HTTP 200, nonce and expiresAt returned"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T17_CODE body=$T17_BODY"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 18 — POST /api/identity/verify with valid signed NIP-27235 event
|
||||||
|
sep "Test 18 — POST /api/identity/verify (valid)"
|
||||||
|
if [[ -n "$CHALLENGE_NONCE" ]]; then
|
||||||
|
VALID_EVENT_JSON=$(node scripts/gen_nostr_event.js "$CHALLENGE_NONCE")
|
||||||
|
T18_RES=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/identity/verify" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$VALID_EVENT_JSON")
|
||||||
|
T18_BODY=$(echo "$T18_RES" | sed '$d')
|
||||||
|
T18_CODE=$(echo "$T18_RES" | tail -n1)
|
||||||
|
NOSTR_TOKEN=$(jq_field "$T18_BODY" '.nostr_token')
|
||||||
|
IDENTITY_PUBKEY=$(jq_field "$T18_BODY" '.pubkey')
|
||||||
|
TRUST_TIER=$(jq_field "$T18_BODY" '.trust')
|
||||||
|
|
||||||
|
if [[ "$T18_CODE" == "200" && -n "$NOSTR_TOKEN" && "$IDENTITY_PUBKEY" == "$NOSTR_PUB_KEY" && -n "$TRUST_TIER" ]]; then
|
||||||
|
note PASS "HTTP 200, nostr_token, pubkey, trust returned"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T18_CODE body=$T18_BODY"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
note SKIP "No challenge nonce from T17 — skipping Test 18"
|
||||||
|
SKIP=$((SKIP+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 19 — GET /api/estimate with X-Nostr-Token header for a new identity
|
||||||
|
sep "Test 19 — GET /api/estimate (free tier)"
|
||||||
|
if [[ -n "$NOSTR_TOKEN" ]]; then
|
||||||
|
T19_RES=$(curl -s -w "\n%{http_code}" "$BASE/api/estimate" -H "X-Nostr-Token: $NOSTR_TOKEN")
|
||||||
|
T19_BODY=$(echo "$T19_RES" | sed '$d')
|
||||||
|
T19_CODE=$(echo "$T19_RES" | tail -n1)
|
||||||
|
FREE_TIER_SERVE=$(jq_field "$T19_BODY" '.free_tier.serve')
|
||||||
|
|
||||||
|
if [[ "$T19_CODE" == "200" && "$FREE_TIER_SERVE" == "free" ]]; then
|
||||||
|
note PASS "HTTP 200, free_tier.serve is 'free'"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T19_CODE body=$T19_BODY"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
note SKIP "No nostr_token from T18 — skipping Test 19"
|
||||||
|
SKIP=$((SKIP+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 20 — POST /api/identity/verify with invalid signature
|
||||||
|
sep "Test 20 — POST /api/identity/verify (invalid signature)"
|
||||||
|
if [[ -n "$CHALLENGE_NONCE" ]]; then
|
||||||
|
INVALID_PRIV_KEY=$(node -e "const { generatePrivateKey } = require('nostr-tools'); console.log(generatePrivateKey());")
|
||||||
|
# Generate a valid event but with a different (invalid) private key
|
||||||
|
INVALID_EVENT_JSON=$(node -e "const { getPublicKey, finalizeEvent } = require('nostr-tools'); const privateKey = '$INVALID_PRIV_KEY'; const event = finalizeEvent({ kind: 27235, created_at: Math.floor(Date.now() / 1000), tags: [['challenge', '$CHALLENGE_NONCE']], content: 'NIP-27235 challenge response' }, privateKey); console.log(JSON.stringify(event));")
|
||||||
|
|
||||||
|
T20_RES=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/identity/verify" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$INVALID_EVENT_JSON")
|
||||||
|
T20_CODE=$(echo "$T20_RES" | tail -n1)
|
||||||
|
|
||||||
|
if [[ "$T20_CODE" == "401" ]]; then
|
||||||
|
note PASS "HTTP 401 for invalid signature"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T20_CODE"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
note SKIP "No challenge nonce from T17 — skipping Test 20"
|
||||||
|
SKIP=$((SKIP+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 21 — POST /api/identity/verify with expired nonce
|
||||||
|
sep "Test 21 — POST /api/identity/verify (expired nonce)"
|
||||||
|
# We'll generate a new challenge for this test, then wait for it to expire.
|
||||||
|
# Assuming a short expiration for testing purposes (e.g., 5 seconds).
|
||||||
|
# In a real scenario, this might be longer or handled with mocked time.
|
||||||
|
|
||||||
|
T21_CHALLENGE_RES=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/identity/challenge")
|
||||||
|
T21_CHALLENGE_BODY=$(echo "$T21_CHALLENGE_RES" | sed '$d')
|
||||||
|
T21_CHALLENGE_CODE=$(echo "$T21_CHALLENGE_RES" | tail -n1)
|
||||||
|
T21_NONCE=$(jq_field "$T21_CHALLENGE_BODY" '.nonce')
|
||||||
|
|
||||||
|
if [[ "$T21_CHALLENGE_CODE" == "200" && -n "$T21_NONCE" ]]; then
|
||||||
|
note "Waiting 6 seconds for nonce to expire..."
|
||||||
|
sleep 6 # Wait for the nonce to expire (assuming expiry < 6 seconds)
|
||||||
|
|
||||||
|
EXPIRED_EVENT_JSON=$(node scripts/gen_nostr_event.js "$T21_NONCE")
|
||||||
|
T21_RES=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/identity/verify" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$EXPIRED_EVENT_JSON")
|
||||||
|
T21_CODE=$(echo "$T21_RES" | tail -n1)
|
||||||
|
|
||||||
|
if [[ "$T21_CODE" == "401" ]]; then
|
||||||
|
note PASS "HTTP 401 for expired nonce"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T21_CODE"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
note SKIP "Failed to get challenge nonce for T21 — skipping Test 21"
|
||||||
|
SKIP=$((SKIP+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 22 — GET /api/estimate without X-Nostr-Token header
|
||||||
|
sep "Test 22 — GET /api/estimate (no token)"
|
||||||
|
T22_RES=$(curl -s -w "\n%{http_code}" "$BASE/api/estimate")
|
||||||
|
T22_BODY=$(echo "$T22_RES" | sed '$d')
|
||||||
|
T22_CODE=$(echo "$T22_RES" | tail -n1)
|
||||||
|
FREE_TIER_SERVE_NO_TOKEN=$(jq_field "$T22_BODY" '.free_tier.serve')
|
||||||
|
|
||||||
|
if [[ "$T22_CODE" == "200" && ("$FREE_TIER_SERVE_NO_TOKEN" == "pay" || -z "$FREE_TIER_SERVE_NO_TOKEN") ]]; then
|
||||||
|
note PASS "HTTP 200, free_tier.serve is 'pay' or absent without token"
|
||||||
|
PASS=$((PASS+1))
|
||||||
|
else
|
||||||
|
note FAIL "code=$T22_CODE body=$T22_BODY"
|
||||||
|
FAIL=$((FAIL+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 23 — GET /api/estimate with X-Nostr-Token for a trust-exhausted identity
|
||||||
|
sep "Test 23 — GET /api/estimate (trust exhausted)"
|
||||||
|
note SKIP "Test 23 — requires exhausting trust tier (complex setup); skipping for now"
|
||||||
|
SKIP=$((SKIP+1))
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Summary
|
# Summary
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user