From 3efa557976f72e6b898876ce0c1c3736f620f71b Mon Sep 17 00:00:00 2001 From: SwiftHawk Date: Mon, 27 May 2024 14:32:24 +0500 Subject: [PATCH] feat: allow the user to login via nsecbunker using only domain part --- src/constants.ts | 2 ++ src/pages/login/index.tsx | 5 ++-- src/utils/nostr.ts | 50 +++++++++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 src/constants.ts diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..35fa102 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,2 @@ +// Regular expression to validate the NIP-05 identifier +export const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/ diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 8c2f702..948651d 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -21,6 +21,7 @@ import { Dispatch } from '../../store/store' import { npubToHex, queryNip05 } from '../../utils' import styles from './style.module.scss' import { hexToBytes } from '@noble/hashes/utils' +import { NIP05_REGEX } from '../../constants' export const Login = () => { const [searchParams] = useSearchParams() @@ -158,7 +159,7 @@ export const Login = () => { setLoadingSpinnerDesc('') } - if (inputValue.includes('@')) { + if (inputValue.match(NIP05_REGEX)) { const nip05Profile = await queryNip05(inputValue).catch((err) => { toast.error('An error occurred while querying nip05 profile: ' + err) return null @@ -319,7 +320,7 @@ export const Login = () => { if (inputValue.startsWith('npub')) { return loginWithNsecBunker() } - if (inputValue.includes('@')) { + if (inputValue.match(NIP05_REGEX)) { return loginWithNsecBunker() } diff --git a/src/utils/nostr.ts b/src/utils/nostr.ts index 229b7be..48d369e 100644 --- a/src/utils/nostr.ts +++ b/src/utils/nostr.ts @@ -1,6 +1,7 @@ import { nip19, verifyEvent } from 'nostr-tools' import { SignedEvent } from '../types' import axios from 'axios' +import { NIP05_REGEX } from '../constants' /** * @param hexKey hex private or public key @@ -72,18 +73,31 @@ export const verifySignedEvent = (event: SignedEvent) => { } } +/** + * Function to query NIP-05 data and return the public key and relays. + * + * @param {string} nip05 - The NIP-05 identifier in the format "name@domain". + * @returns {Promise<{ pubkey: string, relays: string[] }>} - The public key and an array of relay URLs. + * @throws Will throw an error if the NIP-05 identifier is invalid or if there is an issue with the network request. + */ export const queryNip05 = async ( nip05: string ): Promise<{ pubkey: string relays: string[] }> => { - const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/ const match = nip05.match(NIP05_REGEX) + + // Throw an error if the NIP-05 identifier is invalid if (!match) throw new Error('Invalid nip05') + // Destructure the match result, assigning default value '_' to name if not provided const [_, name = '_', domain] = match + + // Construct the URL to query the NIP-05 data const url = `https://${domain}/.well-known/nostr.json?name=${name}` + + // Perform the network request to get the NIP-05 data const res = await axios(url) .then((res) => { return res.data @@ -93,25 +107,41 @@ export const queryNip05 = async ( throw err }) + // Extract the public key from the response data const pubkey = res.names[name] const relays: string[] = [] + // If a public key is found if (pubkey) { - // check nip46 for user pubkey, if relays found for user, return those - const userRelays = res.nip46?.[pubkey] as string[] - if (userRelays && userRelays.length > 0) { - relays.push(...userRelays) - } else { - // otherwise check nip46 for root user pubkey, if relays found, return those + // Function to add relays if they exist and are not empty + const addRelays = (relayList?: string[]) => { + if (relayList && relayList.length > 0) { + relays.push(...relayList) + } + } + + // Check for user-specific relays in the NIP-46 section of the response data + if (res.nip46) { + addRelays(res.nip46[pubkey] as string[]) + } + + // Check for user-specific relays in the relays section of the response data if not found in NIP-46 + if (relays.length === 0 && res.relays) { + addRelays(res.relays[pubkey] as string[]) + } + + // If no user-specific relays are found, check for root user relays + if (relays.length === 0) { const root = res.names['_'] if (root) { - const rootUserRelays = res.nip46?.[root] as string[] - if (rootUserRelays && rootUserRelays.length > 0) - relays.push(...rootUserRelays) + // Check for root user relays in both NIP-46 and relays sections + addRelays(res.nip46?.[root] as string[]) + addRelays(res.relays?.[root] as string[]) } } } + // Return the public key and the array of relays return { pubkey, relays