nip05.ts raw

   1  import { Pubkey } from '@/domain'
   2  import { LRUCache } from 'lru-cache'
   3  
   4  type TVerifyNip05Result = {
   5    isVerified: boolean
   6    nip05Name: string
   7    nip05Domain: string
   8  }
   9  
  10  function proxyUrl(url: string): string {
  11    const proxyServer = import.meta.env.VITE_PROXY_SERVER
  12    if (proxyServer) {
  13      return `${proxyServer}/sites/${encodeURIComponent(url)}`
  14    }
  15    return url
  16  }
  17  
  18  const verifyNip05ResultCache = new LRUCache<string, TVerifyNip05Result>({
  19    max: 1000,
  20    fetchMethod: (key) => {
  21      const { nip05, pubkey } = JSON.parse(key)
  22      return _verifyNip05(nip05, pubkey)
  23    }
  24  })
  25  
  26  async function _verifyNip05(nip05: string, pubkey: string): Promise<TVerifyNip05Result> {
  27    const [nip05Name, nip05Domain] = nip05?.split('@') || [undefined, undefined]
  28    const result = { isVerified: false, nip05Name, nip05Domain }
  29    if (!nip05Name || !nip05Domain || !pubkey) return result
  30  
  31    try {
  32      const res = await fetch(proxyUrl(getWellKnownNip05Url(nip05Domain, nip05Name)))
  33      const json = await res.json()
  34      if (json.names?.[nip05Name] === pubkey) {
  35        return { ...result, isVerified: true }
  36      }
  37    } catch {
  38      // ignore
  39    }
  40    return result
  41  }
  42  
  43  export async function verifyNip05(nip05: string, pubkey: string): Promise<TVerifyNip05Result> {
  44    const result = await verifyNip05ResultCache.fetch(JSON.stringify({ nip05, pubkey }))
  45    if (result) {
  46      return result
  47    }
  48    const [nip05Name, nip05Domain] = nip05?.split('@') || [undefined, undefined]
  49    return { isVerified: false, nip05Name, nip05Domain }
  50  }
  51  
  52  export function getWellKnownNip05Url(domain: string, name?: string): string {
  53    const url = new URL('/.well-known/nostr.json', `https://${domain}`)
  54    if (name) {
  55      url.searchParams.set('name', name)
  56    }
  57    return url.toString()
  58  }
  59  
  60  export async function fetchPubkeysFromDomain(domain: string): Promise<string[]> {
  61    try {
  62      const res = await fetch(proxyUrl(getWellKnownNip05Url(domain)))
  63      const json = await res.json()
  64      const pubkeySet = new Set<string>()
  65      return Object.values(json.names || {}).filter((pubkey) => {
  66        if (typeof pubkey !== 'string' || !Pubkey.isValidHex(pubkey)) {
  67          return false
  68        }
  69        if (pubkeySet.has(pubkey)) {
  70          return false
  71        }
  72        pubkeySet.add(pubkey)
  73        return true
  74      }) as string[]
  75    } catch (error) {
  76      console.error('Error fetching pubkeys from domain:', error)
  77      return []
  78    }
  79  }
  80