diff --git a/.vscode/settings.json b/.vscode/settings.json index adbacfcb..bd8fa271 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", - "prettier.trailingComma": "all" + "prettier.trailingComma": "all" } diff --git a/src/nwc/NWCClient.test.ts b/src/nwc/NWCClient.test.ts index fa430cbe..c237d53c 100644 --- a/src/nwc/NWCClient.test.ts +++ b/src/nwc/NWCClient.test.ts @@ -51,6 +51,25 @@ describe("parseWalletConnectUrl", () => { ]); }); }); +describe("parseWalletConnectUrl validation", () => { + test("throws when no relay is provided", () => { + expect(() => + NWCClient.parseWalletConnectUrl( + "nostr+walletconnect://abc123", + ), + ).toThrow(); + }); + + test("throws when secret is required but missing", () => { + expect(() => + new NWCClient({ + nostrWalletConnectUrl: + "nostr+walletconnect://abc123?relay=wss://relay.example.com", + }), + ).toThrow(); + }); +}); + describe("NWCClient", () => { test("standard protocol", () => { diff --git a/src/nwc/NWCClient.ts b/src/nwc/NWCClient.ts index cc171ffa..a18668b8 100644 --- a/src/nwc/NWCClient.ts +++ b/src/nwc/NWCClient.ts @@ -81,6 +81,37 @@ export class NWCClient { options: NWCOptions; private _encryptionType: Nip47EncryptionType | undefined; + + + + static validateWalletConnectUrl( + options: NWCOptions, + requireSecret = false, + ) { + if (!options.walletPubkey) { + throw new Error("Invalid WalletConnect URL: missing wallet pubkey"); + } + + if (!options.relayUrls || options.relayUrls.length === 0) { + throw new Error("Invalid WalletConnect URL: no relay URLs provided"); + } + + for (const relay of options.relayUrls) { + try { + new URL(relay); + } catch { + throw new Error(`Invalid relay URL: ${relay}`); + } + } + + if (requireSecret && !options.secret) { + throw new Error( + "Invalid WalletConnect URL: missing secret parameter", + ); + } + } + + static parseWalletConnectUrl(walletConnectUrl: string): NWCOptions { // makes it possible to parse with URL in the different environments (browser/node/...) // parses both new and legacy protocols, with or without "//" @@ -107,13 +138,18 @@ export class NWCClient { if (lud16) { options.lud16 = lud16; } + NWCClient.validateWalletConnectUrl(options); return options; } constructor(options?: NewNWCClientOptions) { if (options && options.nostrWalletConnectUrl) { + const parsed = NWCClient.parseWalletConnectUrl( + options.nostrWalletConnectUrl, + ); + NWCClient.validateWalletConnectUrl(parsed, true); options = { - ...NWCClient.parseWalletConnectUrl(options.nostrWalletConnectUrl), + ...parsed, ...options, }; }