Verify nip05 address, display status
This commit is contained in:
parent
a6517c61a4
commit
4c68be19fe
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
22
html.ts
22
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 ` <span class="verified" title="Verified">✔</span>`;
|
||||
} else {
|
||||
return ` <span class="not-verified" title="Verification failed">✕</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
export async function profilePageHtml(
|
||||
profile: Profile,
|
||||
articles: Article[],
|
||||
): Promise<string> {
|
||||
const title = `${profile.name} on Nostr`;
|
||||
let nip05Html = "";
|
||||
|
||||
if (profile.nip05) {
|
||||
const nip05Verified = await profile.verifyNip05();
|
||||
nip05Html += `<p class="nip05">${profile.nip05}${
|
||||
nip05VerifiedHtml(nip05Verified)
|
||||
}</p>\n`;
|
||||
}
|
||||
|
||||
const body = `
|
||||
<main class="profile-page">
|
||||
@ -129,6 +148,7 @@ export function profilePageHtml(profile: Profile, articles: Article[]): string {
|
||||
<img class="avatar" src="${profile.picture}" alt="User Avatar" />
|
||||
<div class="bio">
|
||||
<h1>${profile.name}</h1>
|
||||
${nip05Html}
|
||||
<p class="about">
|
||||
${profile.about}
|
||||
</p>
|
||||
|
@ -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<boolean> {
|
||||
if (typeof this.data.nip05 !== "undefined") {
|
||||
return verifyNip05Address(this.data.nip05, this.pubkey);
|
||||
} else {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
nostr.ts
22
nostr.ts
@ -113,3 +113,25 @@ export async function replaceNostrUris(markdown: string): Promise<string> {
|
||||
|
||||
return markdown;
|
||||
}
|
||||
|
||||
export async function verifyNip05Address(
|
||||
address: string,
|
||||
pubkey: string,
|
||||
): Promise<boolean> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user