diff --git a/src/Text.js b/src/Text.js index 591a5e31..9144b545 100644 --- a/src/Text.js +++ b/src/Text.js @@ -2,6 +2,7 @@ import { Link } from "react-router-dom"; import Invoice from "./element/Invoice"; import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex } from "./Const"; +import { eventLink, profileLink } from "./Util"; export function extractLinks(fragments) { return fragments.map(f => { @@ -54,11 +55,11 @@ export function extractMentions(fragments, tags, users) { switch (ref.Key) { case "p": { let pUser = users[ref.PubKey]?.name ?? ref.PubKey.substring(0, 8); - return ev.stopPropagation()}>@{pUser}; + return ev.stopPropagation()}>@{pUser}; } case "e": { let eText = ref.Event.substring(0, 8); - return #{eText}; + return #{eText}; } } } diff --git a/src/Util.js b/src/Util.js index 7fc8f003..d1a7a2ba 100644 --- a/src/Util.js +++ b/src/Util.js @@ -1,3 +1,5 @@ +import * as secp from "@noble/secp256k1"; +import { bech32 } from "bech32"; export async function openFile() { return new Promise((resolve, reject) => { @@ -9,3 +11,43 @@ export async function openFile() { elm.click(); }); } + +/** + * Parse bech32 ids + * @param {string} id bech32 id + */ +export function parseId(id) { + const hrp = ["note1", "npub", "nsec"]; + try { + if (hrp.some(a => id.startsWith(a))) { + return bech32ToHex(id); + } + } catch (e) { } + return id; +} + +export function bech32ToHex(str) { + let nKey = bech32.decode(str); + let buff = bech32.fromWords(nKey.words); + return secp.utils.bytesToHex(Uint8Array.from(buff)); +} + +/** + * Convert hex note id to bech32 link url + * @param {string} hex + * @returns + */ +export function eventLink(hex) { + let buf = secp.utils.hexToBytes(hex); + return `/e/${bech32.encode("note1", bech32.toWords(buf))}`; +} + +/** + * Convert hex pubkey to bech32 link url + * @param {string} hex + * @returns + */ +export function profileLink(hex) { + let buf = secp.utils.hexToBytes(hex); + return `/p/${bech32.encode("npub", bech32.toWords(buf))}`; +} \ No newline at end of file diff --git a/src/element/Note.js b/src/element/Note.js index 6b63b956..64df27b6 100644 --- a/src/element/Note.js +++ b/src/element/Note.js @@ -11,6 +11,7 @@ import ProfileImage from "./ProfileImage"; import useEventPublisher from "../feed/EventPublisher"; import { NoteCreator } from "./NoteCreator"; import { extractLinks, extractMentions, extractInvoices } from "../Text"; +import { eventLink } from "../Util"; export default function Note(props) { const navigate = useNavigate(); @@ -52,7 +53,7 @@ export default function Note(props) { function goToEvent(e, id) { if (!window.location.pathname.startsWith("/e/")) { e.stopPropagation(); - navigate(`/e/${id}`); + navigate(eventLink(id)); } } diff --git a/src/element/ProfileImage.js b/src/element/ProfileImage.js index e9b3c85c..977d574b 100644 --- a/src/element/ProfileImage.js +++ b/src/element/ProfileImage.js @@ -1,11 +1,10 @@ -import { useMemo } from "react"; - -import { Link, useNavigate } from "react-router-dom"; - -import useProfile from "../feed/ProfileFeed"; +import "./ProfileImage.css"; import Nostrich from "../nostrich.jpg"; -import "./ProfileImage.css"; +import { useMemo } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import useProfile from "../feed/ProfileFeed"; +import { profileLink } from "../Util"; export default function ProfileImage(props) { const pubkey = props.pubkey; @@ -25,9 +24,9 @@ export default function ProfileImage(props) { }, [user]); return (