1c45f23f38fa15ba70bf4c4555e0b1fd778741447661e371209ae609c50b4da5.json raw
1 {"ast":null,"code":"import _asyncToGenerator from \"/home/mleku/src/orly.dev/next/signer/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js\";\n/**\n * NIP-42 Relay Authentication\n *\n * Handles WebSocket connections to relays that require authentication.\n * When a relay sends an AUTH challenge, this module signs the challenge\n * and authenticates before proceeding with event publishing.\n */\nimport { finalizeEvent, getPublicKey } from 'nostr-tools';\n/**\n * Create a NIP-42 authentication event (kind 22242)\n */\nfunction createAuthEvent(relayUrl, challenge, privateKeyHex) {\n const unsignedEvent = {\n kind: 22242,\n created_at: Math.floor(Date.now() / 1000),\n tags: [['relay', relayUrl], ['challenge', challenge]],\n content: ''\n };\n // Convert hex private key to Uint8Array\n const privkeyBytes = hexToBytes(privateKeyHex);\n return finalizeEvent(unsignedEvent, privkeyBytes);\n}\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToBytes(hex) {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes;\n}\n/**\n * Connect to a relay with NIP-42 authentication support\n *\n * @param relayUrl - The relay WebSocket URL (e.g., wss://relay.example.com)\n * @param privateKeyHex - The private key in hex format for signing\n * @param timeoutMs - Connection and authentication timeout in milliseconds\n * @returns Promise resolving to authenticated connection or null if failed\n */\nexport function connectWithAuth(_x, _x2) {\n return _connectWithAuth.apply(this, arguments);\n}\n/**\n * Publish an event to a relay with NIP-42 authentication support\n *\n * This function handles the complete flow:\n * 1. Connect to relay\n * 2. Handle AUTH challenge if sent\n * 3. Publish the event\n * 4. Wait for OK response\n * 5. Close connection\n *\n * @param relayUrl - The relay WebSocket URL\n * @param signedEvent - The already-signed Nostr event to publish\n * @param privateKeyHex - Private key for AUTH (if required)\n * @param timeoutMs - Timeout for the entire operation\n * @returns Promise resolving to publish result\n */\nfunction _connectWithAuth() {\n _connectWithAuth = _asyncToGenerator(function* (relayUrl, privateKeyHex, timeoutMs = 10000) {\n return new Promise(resolve => {\n const timeout = setTimeout(() => {\n ws.close();\n resolve(null);\n }, timeoutMs);\n const ws = new WebSocket(relayUrl);\n const pubkey = getPublicKey(hexToBytes(privateKeyHex));\n ws.onopen = () => {\n // Connection open, wait for AUTH challenge or proceed directly\n };\n ws.onmessage = event => {\n try {\n const message = JSON.parse(event.data);\n const messageType = message[0];\n if (messageType === 'AUTH') {\n // Relay sent an auth challenge\n const challenge = message[1];\n const authEvent = createAuthEvent(relayUrl, challenge, privateKeyHex);\n // Send AUTH response\n ws.send(JSON.stringify(['AUTH', authEvent]));\n } else if (messageType === 'OK') {\n // Check if this is the AUTH response\n const success = message[2];\n const msg = message[3] || '';\n if (success) {\n clearTimeout(timeout);\n resolve({\n ws,\n url: relayUrl,\n authenticated: true,\n pubkey\n });\n } else {\n console.error(`Auth failed for ${relayUrl}: ${msg}`);\n clearTimeout(timeout);\n ws.close();\n resolve(null);\n }\n } else if (messageType === 'NOTICE') {\n // Some relays don't require auth - connection is ready\n clearTimeout(timeout);\n resolve({\n ws,\n url: relayUrl,\n authenticated: false,\n pubkey\n });\n }\n } catch {\n // Ignore parse errors\n }\n };\n ws.onerror = () => {\n clearTimeout(timeout);\n resolve(null);\n };\n ws.onclose = () => {\n clearTimeout(timeout);\n };\n // For relays that don't send AUTH challenge, resolve after short delay\n setTimeout(() => {\n if (ws.readyState === WebSocket.OPEN) {\n clearTimeout(timeout);\n resolve({\n ws,\n url: relayUrl,\n authenticated: false,\n // No auth was required\n pubkey\n });\n }\n }, 2000); // Wait 2 seconds for potential AUTH challenge\n });\n });\n return _connectWithAuth.apply(this, arguments);\n}\nexport function publishEventWithAuth(_x3, _x4, _x5) {\n return _publishEventWithAuth.apply(this, arguments);\n}\n/**\n * Publish an event to multiple relays with NIP-42 support\n *\n * @param relayUrls - Array of relay WebSocket URLs\n * @param signedEvent - The already-signed Nostr event to publish\n * @param privateKeyHex - Private key for AUTH (if required)\n * @returns Promise resolving to array of publish results\n */\nfunction _publishEventWithAuth() {\n _publishEventWithAuth = _asyncToGenerator(function* (relayUrl, signedEvent, privateKeyHex, timeoutMs = 15000) {\n return new Promise(resolve => {\n const timeout = setTimeout(() => {\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.close();\n }\n resolve({\n relay: relayUrl,\n success: false,\n message: 'Timeout'\n });\n }, timeoutMs);\n let ws;\n let authenticated = false;\n let eventSent = false;\n try {\n ws = new WebSocket(relayUrl);\n } catch (e) {\n clearTimeout(timeout);\n resolve({\n relay: relayUrl,\n success: false,\n message: `Connection failed: ${e}`\n });\n return;\n }\n const sendEvent = () => {\n if (!eventSent && ws.readyState === WebSocket.OPEN) {\n eventSent = true;\n ws.send(JSON.stringify(['EVENT', signedEvent]));\n }\n };\n ws.onopen = () => {\n // Wait a moment for potential AUTH challenge before sending event\n setTimeout(() => {\n if (!authenticated) {\n // No auth challenge received, try sending event directly\n sendEvent();\n }\n }, 500);\n };\n ws.onmessage = event => {\n try {\n const message = JSON.parse(event.data);\n const messageType = message[0];\n if (messageType === 'AUTH') {\n // Relay requires authentication\n const challenge = message[1];\n const authEvent = createAuthEvent(relayUrl, challenge, privateKeyHex);\n ws.send(JSON.stringify(['AUTH', authEvent]));\n authenticated = true;\n } else if (messageType === 'OK') {\n const eventId = message[1];\n const success = message[2];\n const msg = message[3] || '';\n // Check if this is our event or AUTH response\n if (eventId === signedEvent.id) {\n // This is the response to our published event\n clearTimeout(timeout);\n ws.close();\n if (success) {\n resolve({\n relay: relayUrl,\n success: true,\n message: 'Published successfully'\n });\n } else {\n // Check if we need to retry after auth\n if (msg.includes('auth-required') && !authenticated) {\n // Relay requires auth but didn't send challenge\n // This shouldn't normally happen\n resolve({\n relay: relayUrl,\n success: false,\n message: 'Auth required but no challenge received'\n });\n } else {\n resolve({\n relay: relayUrl,\n success: false,\n message: msg || 'Publish rejected'\n });\n }\n }\n } else if (authenticated && !eventSent) {\n // This is the OK response to our AUTH\n if (success) {\n // Auth succeeded, now send the event\n sendEvent();\n } else {\n clearTimeout(timeout);\n ws.close();\n resolve({\n relay: relayUrl,\n success: false,\n message: `Authentication failed: ${msg}`\n });\n }\n }\n } else if (messageType === 'NOTICE') {\n // Log notices but don't fail\n console.log(`Relay ${relayUrl} notice: ${message[1]}`);\n }\n } catch {\n // Ignore parse errors\n }\n };\n ws.onerror = () => {\n clearTimeout(timeout);\n resolve({\n relay: relayUrl,\n success: false,\n message: 'Connection error'\n });\n };\n ws.onclose = () => {\n // If we haven't resolved yet, treat as failure\n clearTimeout(timeout);\n };\n });\n });\n return _publishEventWithAuth.apply(this, arguments);\n}\nexport function publishToRelaysWithAuth(_x6, _x7, _x8) {\n return _publishToRelaysWithAuth.apply(this, arguments);\n}\nfunction _publishToRelaysWithAuth() {\n _publishToRelaysWithAuth = _asyncToGenerator(function* (relayUrls, signedEvent, privateKeyHex) {\n const results = yield Promise.all(relayUrls.map(url => publishEventWithAuth(url, signedEvent, privateKeyHex)));\n return results;\n });\n return _publishToRelaysWithAuth.apply(this, arguments);\n}","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}