From b7a49e926aedab6a839806e911ffc52fc61c4eba Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sat, 4 Jan 2025 14:57:31 -0800 Subject: [PATCH 1/5] update for nostr-tools 2.10.4 --- package-lock.json | 56 +++++++++++++++++++++----- package.json | 2 +- server/notification-providers/nostr.js | 27 +++++-------- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d3f58b4d..03d94de45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "2.0.0-beta.0", + "version": "2.0.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "2.0.0-beta.0", + "version": "2.0.0-beta.1", "license": "MIT", "dependencies": { "@grpc/grpc-js": "~1.8.22", @@ -60,7 +60,7 @@ "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", "nodemailer": "~6.9.13", - "nostr-tools": "^1.13.1", + "nostr-tools": "^2.10.4", "notp": "~2.0.3", "openid-client": "^5.4.2", "password-hash": "~1.2.2", @@ -2838,9 +2838,9 @@ } }, "node_modules/@noble/ciphers": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.2.0.tgz", - "integrity": "sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", + "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -12582,18 +12582,21 @@ } }, "node_modules/nostr-tools": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-1.17.0.tgz", - "integrity": "sha512-LZmR8GEWKZeElbFV5Xte75dOeE9EFUW/QLI1Ncn3JKn0kFddDKEfBbFN8Mu4TMs+L4HR/WTPha2l+PPuRnJcMw==", + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.10.4.tgz", + "integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==", "license": "Unlicense", "dependencies": { - "@noble/ciphers": "0.2.0", - "@noble/curves": "1.1.0", + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", "@scure/bip39": "1.2.1" }, + "optionalDependencies": { + "nostr-wasm": "0.1.0" + }, "peerDependencies": { "typescript": ">=5.0.0" }, @@ -12603,6 +12606,37 @@ } } }, + "node_modules/nostr-tools/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-wasm": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.1.0.tgz", + "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==", + "license": "MIT", + "optional": true + }, "node_modules/notp": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/notp/-/notp-2.0.3.tgz", diff --git a/package.json b/package.json index 6af61da25..e1d8166fb 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", "nodemailer": "~6.9.13", - "nostr-tools": "^1.13.1", + "nostr-tools": "^2.10.4", "notp": "~2.0.3", "openid-client": "^5.4.2", "password-hash": "~1.2.2", diff --git a/server/notification-providers/nostr.js b/server/notification-providers/nostr.js index 87847382e..bb2fd5deb 100644 --- a/server/notification-providers/nostr.js +++ b/server/notification-providers/nostr.js @@ -1,11 +1,9 @@ const NotificationProvider = require("./notification-provider"); const { - relayInit, - getPublicKey, - getEventHash, - getSignature, + finalizeEvent, + Relay, nip04, - nip19 + nip19, } = require("nostr-tools"); // polyfills for node versions @@ -31,7 +29,6 @@ class Nostr extends NotificationProvider { const createdAt = Math.floor(Date.now() / 1000); const senderPrivateKey = await this.getPrivateKey(notification.sender); - const senderPublicKey = getPublicKey(senderPrivateKey); const recipientsPublicKeys = await this.getPublicKeys(notification.recipients); // Create NIP-04 encrypted direct message event for each recipient @@ -40,35 +37,29 @@ class Nostr extends NotificationProvider { const ciphertext = await nip04.encrypt(senderPrivateKey, recipientPublicKey, msg); let event = { kind: 4, - pubkey: senderPublicKey, created_at: createdAt, tags: [[ "p", recipientPublicKey ]], content: ciphertext, }; - event.id = getEventHash(event); - event.sig = getSignature(event, senderPrivateKey); - events.push(event); + const signedEvent = finalizeEvent(event, senderPrivateKey); + events.push(signedEvent); } // Publish events to each relay const relays = notification.relays.split("\n"); let successfulRelays = 0; - - // Connect to each relay for (const relayUrl of relays) { - const relay = relayInit(relayUrl); try { - await relay.connect(); - successfulRelays++; + const relay = await Relay.connect(relayUrl); // Publish events for (const event of events) { - relay.publish(event); + await relay.publish(event); } + relay.close(); + successfulRelays++; } catch (error) { continue; - } finally { - relay.close(); } } From 696ccfaec38f5fbeaa2839e88b3215a83e39058d Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sat, 4 Jan 2025 20:26:01 -0800 Subject: [PATCH 2/5] 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 From e421c4eda563649a8aa18a5842c58f3a6e985fea Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sun, 5 Jan 2025 10:07:02 -0800 Subject: [PATCH 3/5] always close relay connections --- server/notification-providers/nostr.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/notification-providers/nostr.js b/server/notification-providers/nostr.js index 1775feb76..a6bb57117 100644 --- a/server/notification-providers/nostr.js +++ b/server/notification-providers/nostr.js @@ -70,10 +70,11 @@ class Nostr extends NotificationProvider { for (let i = eventIndex; i < events.length; i++) { await relay.publish(events[i]); } - relay.close(); successfulRelays++; } catch (error) { console.error(`Failed to publish event to ${relayUrl}:`, error); + } finally { + relay.close(); } } From 81e7e920ded8dcdde9feded5056a72d3af92da63 Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sun, 5 Jan 2025 10:07:22 -0800 Subject: [PATCH 4/5] remove unused code --- server/notification-providers/nostr.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/server/notification-providers/nostr.js b/server/notification-providers/nostr.js index a6bb57117..d4cbfb630 100644 --- a/server/notification-providers/nostr.js +++ b/server/notification-providers/nostr.js @@ -5,7 +5,6 @@ const { kinds, nip04, nip19, - nip42, } = require("nostr-tools"); // polyfills for node versions @@ -85,17 +84,6 @@ 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 From a99d25bf3c299109b6caf465477b040b5d7987ad Mon Sep 17 00:00:00 2001 From: zappityzap Date: Sun, 5 Jan 2025 10:07:47 -0800 Subject: [PATCH 5/5] improve error messages --- server/notification-providers/nostr.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/notification-providers/nostr.js b/server/notification-providers/nostr.js index d4cbfb630..72f0bb621 100644 --- a/server/notification-providers/nostr.js +++ b/server/notification-providers/nostr.js @@ -95,7 +95,7 @@ class Nostr extends NotificationProvider { const { data } = senderDecodeResult; return data; } catch (error) { - throw new Error(`Failed to get private key: ${error.message}`); + throw new Error(`Failed to decode private key for sender ${sender}: ${error.message}`); } } @@ -114,10 +114,10 @@ class Nostr extends NotificationProvider { if (type === "npub") { publicKeys.push(data); } else { - throw new Error("not an npub"); + throw new Error(`Recipient ${recipient} is not an npub`); } } catch (error) { - throw new Error(`Error decoding recipient: ${error}`); + throw new Error(`Error decoding recipient ${recipient}: ${error}`); } } return publicKeys;