diff --git a/.changeset/nasty-pumpkins-dance.md b/.changeset/nasty-pumpkins-dance.md new file mode 100644 index 000000000..61c5629c9 --- /dev/null +++ b/.changeset/nasty-pumpkins-dance.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add support for bunker://npub@relay NIP-46 login diff --git a/src/services/nostr-connect.ts b/src/services/nostr-connect.ts index 47c461aa7..d5d110c40 100644 --- a/src/services/nostr-connect.ts +++ b/src/services/nostr-connect.ts @@ -3,7 +3,7 @@ import dayjs from "dayjs"; import { nanoid } from "nanoid"; import NostrMultiSubscription from "../classes/nostr-multi-subscription"; -import { getPubkeyFromDecodeResult, isHexKey } from "../helpers/nip19"; +import { getPubkeyFromDecodeResult, isHexKey, normalizeToHexPubkey } from "../helpers/nip19"; import { createSimpleQueryMap } from "../helpers/nostr/filter"; import { logger } from "../helpers/debug"; import { DraftNostrEvent, NostrEvent, isPTag } from "../types/nostr-event"; @@ -11,6 +11,7 @@ import createDefer, { Deferred } from "../classes/deferred"; import { truncatedId } from "../helpers/nostr/events"; import { NostrConnectAccount } from "./account"; import { bytesToHex, hexToBytes } from "@noble/hashes/utils"; +import { normalizeRelayURL } from "../helpers/relay"; export enum NostrConnectMethod { Connect = "connect", @@ -181,12 +182,24 @@ class NostrConnectService { return client; } + fromBunkerAddress(address: string) { + const parts = address.replace("bunker://", "").split("@"); + if (parts.length !== 2) throw new Error("Invalid bunker address"); + const pubkey = normalizeToHexPubkey(parts[0]); + const pathRelay = normalizeRelayURL("wss://" + parts[1]); + if (!pubkey || !isHexKey(pubkey)) throw new Error("Missing pubkey"); + + return this.getClient(pubkey) || this.createClient(pubkey, [pathRelay]); + } fromBunkerURI(uri: string) { const url = new URL(uri); - const pubkey = url.pathname.replace(/^\/\//, ""); + const pathParts = url.pathname.replace(/^\/\//, "").split("@"); + const pubkey = pathParts[0]; + const pathRelay = pathParts[1] as string | undefined; if (!isHexKey(pubkey)) throw new Error("Invalid connection URI"); const relays = url.searchParams.getAll("relay"); + if (pathRelay) relays.push(pathRelay); if (relays.length === 0) throw new Error("Missing relays"); return this.getClient(pubkey) || this.createClient(pubkey, relays); diff --git a/src/views/signin/nostr-connect.tsx b/src/views/signin/nostr-connect.tsx index 9747d6cf2..e12fe568b 100644 --- a/src/views/signin/nostr-connect.tsx +++ b/src/views/signin/nostr-connect.tsx @@ -18,7 +18,9 @@ export default function LoginNostrConnectView() { setLoading("Connecting..."); let client: NostrConnectClient; if (uri.startsWith("bunker://")) { - client = nostrConnectService.fromBunkerURI(uri); + if (uri.includes("@")) client = nostrConnectService.fromBunkerAddress(uri); + else client = nostrConnectService.fromBunkerURI(uri); + await client.connect(); } else if (uri.startsWith("npub")) { client = nostrConnectService.fromNsecBunkerToken(uri);