Merge pull request 'feat: allow the user to login via nsecbunker using only domain part' (#79) from issue-77 into main
All checks were successful
Release / build_and_release (push) Successful in 1m6s

Reviewed-on: https://git.sigit.io/sig/it/pulls/79
Reviewed-by: Y <yury@4gl.io>
This commit is contained in:
s 2024-05-27 10:02:08 +00:00
commit 5c286c6b97
3 changed files with 45 additions and 12 deletions

2
src/constants.ts Normal file
View File

@ -0,0 +1,2 @@
// Regular expression to validate the NIP-05 identifier
export const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/

View File

@ -21,6 +21,7 @@ import { Dispatch } from '../../store/store'
import { npubToHex, queryNip05 } from '../../utils' import { npubToHex, queryNip05 } from '../../utils'
import styles from './style.module.scss' import styles from './style.module.scss'
import { hexToBytes } from '@noble/hashes/utils' import { hexToBytes } from '@noble/hashes/utils'
import { NIP05_REGEX } from '../../constants'
export const Login = () => { export const Login = () => {
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
@ -158,7 +159,7 @@ export const Login = () => {
setLoadingSpinnerDesc('') setLoadingSpinnerDesc('')
} }
if (inputValue.includes('@')) { if (inputValue.match(NIP05_REGEX)) {
const nip05Profile = await queryNip05(inputValue).catch((err) => { const nip05Profile = await queryNip05(inputValue).catch((err) => {
toast.error('An error occurred while querying nip05 profile: ' + err) toast.error('An error occurred while querying nip05 profile: ' + err)
return null return null
@ -319,7 +320,7 @@ export const Login = () => {
if (inputValue.startsWith('npub')) { if (inputValue.startsWith('npub')) {
return loginWithNsecBunker() return loginWithNsecBunker()
} }
if (inputValue.includes('@')) { if (inputValue.match(NIP05_REGEX)) {
return loginWithNsecBunker() return loginWithNsecBunker()
} }

View File

@ -1,6 +1,7 @@
import { nip19, verifyEvent } from 'nostr-tools' import { nip19, verifyEvent } from 'nostr-tools'
import { SignedEvent } from '../types' import { SignedEvent } from '../types'
import axios from 'axios' import axios from 'axios'
import { NIP05_REGEX } from '../constants'
/** /**
* @param hexKey hex private or public key * @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 ( export const queryNip05 = async (
nip05: string nip05: string
): Promise<{ ): Promise<{
pubkey: string pubkey: string
relays: string[] relays: string[]
}> => { }> => {
const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/
const match = nip05.match(NIP05_REGEX) const match = nip05.match(NIP05_REGEX)
// Throw an error if the NIP-05 identifier is invalid
if (!match) throw new Error('Invalid nip05') if (!match) throw new Error('Invalid nip05')
// Destructure the match result, assigning default value '_' to name if not provided
const [_, name = '_', domain] = match const [_, name = '_', domain] = match
// Construct the URL to query the NIP-05 data
const url = `https://${domain}/.well-known/nostr.json?name=${name}` 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) const res = await axios(url)
.then((res) => { .then((res) => {
return res.data return res.data
@ -93,25 +107,41 @@ export const queryNip05 = async (
throw err throw err
}) })
// Extract the public key from the response data
const pubkey = res.names[name] const pubkey = res.names[name]
const relays: string[] = [] const relays: string[] = []
// If a public key is found
if (pubkey) { if (pubkey) {
// check nip46 for user pubkey, if relays found for user, return those // Function to add relays if they exist and are not empty
const userRelays = res.nip46?.[pubkey] as string[] const addRelays = (relayList?: string[]) => {
if (userRelays && userRelays.length > 0) { if (relayList && relayList.length > 0) {
relays.push(...userRelays) relays.push(...relayList)
} else { }
// otherwise check nip46 for root user pubkey, if relays found, return those }
// 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['_'] const root = res.names['_']
if (root) { if (root) {
const rootUserRelays = res.nip46?.[root] as string[] // Check for root user relays in both NIP-46 and relays sections
if (rootUserRelays && rootUserRelays.length > 0) addRelays(res.nip46?.[root] as string[])
relays.push(...rootUserRelays) addRelays(res.relays?.[root] as string[])
} }
} }
} }
// Return the public key and the array of relays
return { return {
pubkey, pubkey,
relays relays