From 011d69482a9ba600b0265a4002518969cd709c97 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:35:14 -0400 Subject: [PATCH] Prefer nip04 encryption fallback for implicit wallets --- js/payments/nwcClient.js | 16 +++++- tests/nwc-client.test.mjs | 109 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/js/payments/nwcClient.js b/js/payments/nwcClient.js index 1df36acc..5e47f4dd 100644 --- a/js/payments/nwcClient.js +++ b/js/payments/nwcClient.js @@ -627,7 +627,8 @@ async function ensureEncryption(context) { } } - const { schemes: walletSchemes } = getWalletSupportedEncryption(infoEvent); + const { schemes: walletSchemes, explicit: walletSchemesExplicit } = + getWalletSupportedEncryption(infoEvent); const candidates = getEncryptionCandidates(context).filter((candidate) => { return !state.unsupported.has(candidate.scheme); }); @@ -636,6 +637,19 @@ async function ensureEncryption(context) { ? candidates.filter((candidate) => walletSchemes.includes(candidate.scheme)) : candidates; + if ( + compatibleCandidates.length > 1 && + (!walletSchemesExplicit || !walletSchemes.includes("nip44_v2")) + ) { + const nip04Index = compatibleCandidates.findIndex( + (candidate) => candidate.scheme === "nip04" + ); + if (nip04Index > 0) { + const [nip04Candidate] = compatibleCandidates.splice(nip04Index, 1); + compatibleCandidates.unshift(nip04Candidate); + } + } + if (compatibleCandidates.length) { const selected = compatibleCandidates[0]; context.encryption = selected; diff --git a/tests/nwc-client.test.mjs b/tests/nwc-client.test.mjs index a4c5ef50..ab8812b4 100644 --- a/tests/nwc-client.test.mjs +++ b/tests/nwc-client.test.mjs @@ -65,6 +65,14 @@ await (async () => { }, }, }, + nip04: { + async encrypt() { + return "nip04"; + }, + async decrypt() { + return "nip04"; + }, + }, }; const walletPubkey = "b".repeat(64); @@ -105,6 +113,107 @@ await (async () => { resetWalletClient(); })(); +await (async () => { + resetWalletClient(); + + window.NostrTools = { + getPublicKey() { + return "c".repeat(64); + }, + nip44: { + v2: { + async encrypt(plaintext, key) { + return `nip44:${key}:${plaintext}`; + }, + async decrypt(ciphertext, key) { + return `nip44:${key}:${ciphertext}`; + }, + utils: { + getConversationKey(secretBytes, pubkey) { + return `key-${pubkey}-${secretBytes.length}`; + }, + }, + }, + }, + nip04: { + async encrypt() { + return "nip04"; + }, + async decrypt() { + return "nip04"; + }, + }, + }; + + const walletPubkey = "b".repeat(64); + const secretKey = "a".repeat(64); + const relays = ["wss://relay.one.example"]; + const uri = + `nostr+walletconnect://${walletPubkey}` + + `?relay=${encodeURIComponent(relays[0])}` + + `&secret=${secretKey}`; + + const context = ensureActiveState({ nwcUri: uri }); + context.infoEvent = { kind: 13194, tags: [] }; + + const encryption = await __TESTING__.ensureEncryptionForContext(context); + assert.equal(encryption.scheme, "nip04"); + + resetWalletClient(); +})(); + +await (async () => { + resetWalletClient(); + + window.NostrTools = { + getPublicKey() { + return "c".repeat(64); + }, + nip44: { + v2: { + async encrypt(plaintext, key) { + return `nip44:${key}:${plaintext}`; + }, + async decrypt(ciphertext, key) { + return `nip44:${key}:${ciphertext}`; + }, + utils: { + getConversationKey(secretBytes, pubkey) { + return `key-${pubkey}-${secretBytes.length}`; + }, + }, + }, + }, + nip04: { + async encrypt() { + return "nip04"; + }, + async decrypt() { + return "nip04"; + }, + }, + }; + + const walletPubkey = "b".repeat(64); + const secretKey = "a".repeat(64); + const relays = ["wss://relay.one.example"]; + const uri = + `nostr+walletconnect://${walletPubkey}` + + `?relay=${encodeURIComponent(relays[0])}` + + `&secret=${secretKey}`; + + const context = ensureActiveState({ nwcUri: uri }); + context.infoEvent = { + kind: 13194, + tags: [["encryption", "nip04"]], + }; + + const encryption = await __TESTING__.ensureEncryptionForContext(context); + assert.equal(encryption.scheme, "nip04"); + + resetWalletClient(); +})(); + await (async () => { resetWalletClient();