From 696ccfaec38f5fbeaa2839e88b3215a83e39058d Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sat, 4 Jan 2025 20:26:01 -0800 Subject: [PATCH] support relay authentication --- server/notification-providers/nostr.js | 39 +++++++++++++++++++++----- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/server/notification-providers/nostr.js b/server/notification-providers/nostr.js index bb2fd5deb..1775feb76 100644 --- a/server/notification-providers/nostr.js +++ b/server/notification-providers/nostr.js @@ -2,8 +2,10 @@ const NotificationProvider = require("./notification-provider"); const { finalizeEvent, Relay, + kinds, nip04, nip19, + nip42, } = require("nostr-tools"); // polyfills for node versions @@ -36,7 +38,7 @@ class Nostr extends NotificationProvider { for (const recipientPublicKey of recipientsPublicKeys) { const ciphertext = await nip04.encrypt(senderPrivateKey, recipientPublicKey, msg); let event = { - kind: 4, + kind: kinds.EncryptedDirectMessage, created_at: createdAt, tags: [[ "p", recipientPublicKey ]], content: ciphertext, @@ -49,17 +51,29 @@ class Nostr extends NotificationProvider { const relays = notification.relays.split("\n"); let successfulRelays = 0; for (const relayUrl of relays) { - try { - const relay = await Relay.connect(relayUrl); + const relay = await Relay.connect(relayUrl); + let eventIndex = 0; - // Publish events - for (const event of events) { - await relay.publish(event); + // Authenticate to the relay, if required + try { + await relay.publish(events[0]); + eventIndex = 1; + } catch (error) { + if (relay.challenge) { + await relay.auth(async (evt) => { + return finalizeEvent(evt, senderPrivateKey); + }); + } + } + + try { + for (let i = eventIndex; i < events.length; i++) { + await relay.publish(events[i]); } relay.close(); successfulRelays++; } catch (error) { - continue; + console.error(`Failed to publish event to ${relayUrl}:`, error); } } @@ -70,6 +84,17 @@ class Nostr extends NotificationProvider { return `${successfulRelays}/${relays.length} relays connected.`; } + /** + * Sign the authentication event + * @param {Relay} relay Relay instance + * @param {string} privateKey Sender's private key + * @returns {Promise} Signed authentication event + */ + async signAuthEvent(relay, privateKey) { + const authEvent = nip42.makeAuthEvent(relay.url, relay.challenge); + return finalizeEvent(authEvent, privateKey); + } + /** * Get the private key for the sender * @param {string} sender Sender to retrieve key for