From 3f0499b96ee95ec1d475471f05a05dfd08f982bf Mon Sep 17 00:00:00 2001 From: ekzyis Date: Fri, 6 Sep 2024 15:20:49 +0200 Subject: [PATCH] Fix ephemeral events missed (#1367) * Fix ephemeral events missed The spec mentions the following: > for kind n such that 20000 <= n < 30000, events are ephemeral, which means they are not expected to be stored by relays. This applies to NWC events. This means that we need to subscribe _before_ we publish the request. See https://github.com/nostr-protocol/nips/blob/master/01.md * Verify events before accepting them --- wallets/nwc/index.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/wallets/nwc/index.js b/wallets/nwc/index.js index 254ac428..fe443968 100644 --- a/wallets/nwc/index.js +++ b/wallets/nwc/index.js @@ -1,7 +1,7 @@ import { Relay } from '@/lib/nostr' import { parseNwcUrl } from '@/lib/url' import { nwcSchema } from '@/lib/validate' -import { finalizeEvent, nip04 } from 'nostr-tools' +import { finalizeEvent, nip04, verifyEvent } from 'nostr-tools' export const name = 'nwc' @@ -52,16 +52,22 @@ export async function nwcCall ({ nwcUrl, method, params }, { logger, timeout } = tags: [['p', walletPubkey]], content: encrypted }, secret) + + // we need to subscribe to the response before publishing the request + // since NWC events are ephemeral (20000 <= kind < 30000) + const subscription = relay.fetch([{ + kinds: [23195], + authors: [walletPubkey], + '#e': [request.id] + }], { timeout }) + await relay.publish(request, { timeout }) logger?.info(`published ${method} request`) logger?.info('waiting for response ...') - const [response] = await relay.fetch([{ - kinds: [23195], - authors: [walletPubkey], - '#e': [request.id] - }], { timeout }) + + const [response] = await subscription if (!response) { throw new Error('no response') @@ -69,13 +75,15 @@ export async function nwcCall ({ nwcUrl, method, params }, { logger, timeout } = logger?.ok('response received') + if (!verifyEvent(response)) throw new Error('invalid response: failed to verify') + const decrypted = await nip04.decrypt(secret, walletPubkey, response.content) const content = JSON.parse(decrypted) if (content.error) throw new Error(content.error.message) if (content.result) return content.result - throw new Error('invalid response') + throw new Error('invalid response: missing error or result') } finally { relay?.close() logger?.info(`closed connection to ${relayUrl}`)