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