diff --git a/src/lib/event-metadata.ts b/src/lib/event-metadata.ts index 383d1bee..d14b7052 100644 --- a/src/lib/event-metadata.ts +++ b/src/lib/event-metadata.ts @@ -57,6 +57,41 @@ export function getRelayListFromEvent(event?: Event | null, blockedRelays?: stri } } +/** Kind 0 JSON `nip05` may be a string or string[]; tags are always strings. */ +function firstNip05StringFromJson(raw: unknown): string | undefined { + if (typeof raw === 'string') { + const t = raw.trim() + return t || undefined + } + if (Array.isArray(raw)) { + for (const x of raw) { + if (typeof x === 'string') { + const t = x.trim() + if (t) return t + } + } + } + return undefined +} + +function nip05ListFromJson(raw: unknown): string[] | undefined { + const out: string[] = [] + const seen = new Set() + const add = (s: string) => { + const t = s.trim() + if (!t || seen.has(t)) return + seen.add(t) + out.push(t) + } + if (typeof raw === 'string') add(raw) + else if (Array.isArray(raw)) { + for (const x of raw) { + if (typeof x === 'string') add(x) + } + } + return out.length > 0 ? out : undefined +} + export function getProfileFromEvent(event: Event) { // Parse JSON content as fallback let profileObj: any = {} @@ -73,8 +108,10 @@ export function getProfileFromEvent(event: Event) { const lud16Tags = event.tags.filter(tag => tag[0] === 'lud16' && tag[1]).map(tag => tag[1]) // Use first tag entry for single values, or fallback to JSON - const nip05 = nip05Tags.length > 0 ? nip05Tags[0] : profileObj.nip05 - const nip05List = nip05Tags.length > 0 ? nip05Tags : (profileObj.nip05 ? [profileObj.nip05] : undefined) + const nip05 = + nip05Tags.length > 0 ? nip05Tags[0] : firstNip05StringFromJson(profileObj.nip05) + const nip05List = + nip05Tags.length > 0 ? nip05Tags : nip05ListFromJson(profileObj.nip05) const website = websiteTags.length > 0 ? normalizeHttpUrl(websiteTags[0]) diff --git a/src/lib/nip05.ts b/src/lib/nip05.ts index 32bd4d03..72cbbcc1 100644 --- a/src/lib/nip05.ts +++ b/src/lib/nip05.ts @@ -9,16 +9,31 @@ type TVerifyNip05Result = { relays?: string[] } +function asNip05LookupString(value: unknown): string { + if (typeof value === 'string') return value + if (value == null) return '' + if (Array.isArray(value)) { + for (const x of value) { + if (typeof x === 'string' && x.trim()) return x + } + return '' + } + return String(value) +} + const verifyNip05ResultCache = new LRUCache({ max: 1000, fetchMethod: (key) => { - const { nip05, pubkey } = JSON.parse(key) - return _verifyNip05(nip05, pubkey) + const { nip05, pubkey } = JSON.parse(key) as { nip05?: unknown; pubkey?: unknown } + return _verifyNip05(asNip05LookupString(nip05), typeof pubkey === 'string' ? pubkey : '') } }) async function _verifyNip05(nip05: string, pubkey: string): Promise { - const [nip05Name, nip05Domain] = nip05?.split('@') || [undefined, undefined] + const nip05Str = asNip05LookupString(nip05) + const parts = nip05Str ? nip05Str.split('@') : [] + const nip05Name = parts[0] + const nip05Domain = parts[1] const result: TVerifyNip05Result = { isVerified: false, nip05Name, nip05Domain } if (!nip05Name || !nip05Domain || !pubkey) return result @@ -37,12 +52,14 @@ async function _verifyNip05(nip05: string, pubkey: string): Promise { - const result = await verifyNip05ResultCache.fetch(JSON.stringify({ nip05, pubkey })) + const nip05Str = asNip05LookupString(nip05) + const pubkeyStr = typeof pubkey === 'string' ? pubkey : '' + const result = await verifyNip05ResultCache.fetch(JSON.stringify({ nip05: nip05Str, pubkey: pubkeyStr })) if (result) { return result } - const [nip05Name, nip05Domain] = nip05?.split('@') || [undefined, undefined] - return { isVerified: false, nip05Name, nip05Domain } + const parts = nip05Str ? nip05Str.split('@') : [] + return { isVerified: false, nip05Name: parts[0], nip05Domain: parts[1] } } export function getWellKnownNip05Url(domain: string, name?: string): string {