From 4c68be19fe7267ffbaf49b5c0d9f47f3b4a9f306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 25 Oct 2024 17:50:59 +0200 Subject: [PATCH] Verify nip05 address, display status --- assets/css/layout.css | 18 +++++++++++++++++- assets/css/themes/default-light.css | 14 ++++++++++++++ handlers/user-profile.ts | 2 +- html.ts | 22 +++++++++++++++++++++- models/profile.ts | 11 ++++++++++- nostr.ts | 22 ++++++++++++++++++++++ 6 files changed, 85 insertions(+), 4 deletions(-) diff --git a/assets/css/layout.css b/assets/css/layout.css index 0b801f5..18c696f 100644 --- a/assets/css/layout.css +++ b/assets/css/layout.css @@ -108,6 +108,14 @@ main.profile-page header { margin-bottom: 2rem; } +main.profile-page header h1 { + margin-bottom: 0; +} + +main.profile-page header .nip05 { + font-size: 1rem; +} + main.profile-page img.avatar { height: 8rem; width: 8rem; @@ -134,6 +142,14 @@ main article footer { margin-top: 5rem; } +.nip05 .verified, +.nip05 .not-verified { + margin-left: 0.3rem; + padding: 0.1em 0.3em; + border-radius: 5px; + cursor: default; +} + /* Dropdown menu */ .dropdown { @@ -202,7 +218,7 @@ main article footer { margin: 4rem 1rem 8rem 1rem !important; } - .profile-page h1 { + main.profile-page h1 { margin-top: 2rem; } diff --git a/assets/css/themes/default-light.css b/assets/css/themes/default-light.css index fc875d1..5e880b0 100644 --- a/assets/css/themes/default-light.css +++ b/assets/css/themes/default-light.css @@ -68,10 +68,24 @@ main header .meta .name a { color: var(--text-color-body); } +main.profile-page header .nip05 { + color: var(--text-color-discreet); +} + main.profile-page .pubkey { color: var(--text-color-discreet); } +.nip05 .verified { + background-color: #e8e3da; + color: #027739; +} + +.nip05 .not-verified { + background-color: #e8e3da; + color: #770202; +} + /* Dropdown menu */ .dropdown { diff --git a/handlers/user-profile.ts b/handlers/user-profile.ts index cfc4537..e561ee6 100644 --- a/handlers/user-profile.ts +++ b/handlers/user-profile.ts @@ -22,7 +22,7 @@ const userProfileHandler = async function (ctx: Context) { const profile = new Profile(profileEvent, username); const articleEvents = await fetchArticlesByAuthor(pubkey); const articles = articleEvents.map((a) => new Article(a)); - const html = profilePageHtml(profile, articles); + const html = await profilePageHtml(profile, articles); generateOgProfileImage(profile); ctx.response.body = html; diff --git a/html.ts b/html.ts index f4b6f16..9f42b31 100644 --- a/html.ts +++ b/html.ts @@ -120,8 +120,27 @@ function userAddressHtml(profile: Profile) { return html; } -export function profilePageHtml(profile: Profile, articles: Article[]): string { +function nip05VerifiedHtml(verified: boolean): string { + if (verified) { + return ` `; + } else { + return ` `; + } +} + +export async function profilePageHtml( + profile: Profile, + articles: Article[], +): Promise { const title = `${profile.name} on Nostr`; + let nip05Html = ""; + + if (profile.nip05) { + const nip05Verified = await profile.verifyNip05(); + nip05Html += `

${profile.nip05}${ + nip05VerifiedHtml(nip05Verified) + }

\n`; + } const body = `
@@ -129,6 +148,7 @@ export function profilePageHtml(profile: Profile, articles: Article[]): string { User Avatar

${profile.name}

+ ${nip05Html}

${profile.about}

diff --git a/models/profile.ts b/models/profile.ts index fcb9b8d..05e5415 100644 --- a/models/profile.ts +++ b/models/profile.ts @@ -1,4 +1,5 @@ import { nip19, NostrEvent as NEvent } from "@nostr/tools"; +import { verifyNip05Address } from "../nostr.ts"; import { getImageMagickCommand } from "../utils.ts"; import config from "../config.ts"; @@ -43,7 +44,7 @@ export default class Profile { } get nip05(): string | undefined { - return this.data.nip05; + return this.data.nip05?.replace("_@", ""); } get lud16(): string | undefined { @@ -69,4 +70,12 @@ export default class Profile { return this.picture || ""; } } + + verifyNip05(): Promise { + if (typeof this.data.nip05 !== "undefined") { + return verifyNip05Address(this.data.nip05, this.pubkey); + } else { + return Promise.resolve(false); + } + } } diff --git a/nostr.ts b/nostr.ts index 6c7eb5b..49606c8 100644 --- a/nostr.ts +++ b/nostr.ts @@ -113,3 +113,25 @@ export async function replaceNostrUris(markdown: string): Promise { return markdown; } + +export async function verifyNip05Address( + address: string, + pubkey: string, +): Promise { + const [username, host] = address.split("@"); + const url = `https://${host}/.well-known/nostr.json?name=${username}`; + + try { + const res = await fetch(url); + if (res.status === 404 || !res.ok) return false; + const data = await res.json(); + + if (data.names && data.names[username] === pubkey) { + return true; + } else { + return false; + } + } catch (_e) { + return false; + } +}