Use bech32 links for events/profiles
This commit is contained in:
parent
25c292f47c
commit
f864b682f5
@ -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 <Link key={ref.PubKey} to={`/p/${ref.PubKey}`} onClick={(ev) => ev.stopPropagation()}>@{pUser}</Link>;
|
||||
return <Link key={ref.PubKey} to={profileLink(ref.PubKey)} onClick={(ev) => ev.stopPropagation()}>@{pUser}</Link>;
|
||||
}
|
||||
case "e": {
|
||||
let eText = ref.Event.substring(0, 8);
|
||||
return <Link key={ref.Event} to={`/e/${ref.Event}`}>#{eText}</Link>;
|
||||
return <Link key={ref.Event} to={eventLink(ref.Event)}>#{eText}</Link>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
src/Util.js
42
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))}`;
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 (
|
||||
<div className="pfp">
|
||||
<img src={hasImage ? user.picture : Nostrich} onClick={() => navigate(`/p/${pubkey}`)} />
|
||||
<img src={hasImage ? user.picture : Nostrich} onClick={() => navigate(profileLink(pubkey))} />
|
||||
<div>
|
||||
<Link key={pubkey} to={`/p/${pubkey}`}>{name}</Link>
|
||||
<Link key={pubkey} to={profileLink(pubkey)}>{name}</Link>
|
||||
{subHeader ? <div>{subHeader}</div> : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ import { useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import Event from "../nostr/Event";
|
||||
import EventKind from "../nostr/EventKind";
|
||||
import { eventLink } from "../Util";
|
||||
import Note from "./Note";
|
||||
import NoteGhost from "./NoteGhost";
|
||||
|
||||
@ -81,7 +82,7 @@ export default function Thread(props) {
|
||||
return (
|
||||
<>
|
||||
<NoteGhost key={a}>
|
||||
Missing event <Link to={`/e/${a}`}>{a.substring(0, 8)}</Link>
|
||||
Missing event <Link to={eventLink(a)}>{a.substring(0, 8)}</Link>
|
||||
</NoteGhost>
|
||||
{renderChain(a)}
|
||||
</>
|
||||
|
@ -2,10 +2,11 @@ import { useMemo } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Thread from "../element/Thread";
|
||||
import useThreadFeed from "../feed/ThreadFeed";
|
||||
import { parseId } from "../Util";
|
||||
|
||||
export default function EventPage() {
|
||||
const params = useParams();
|
||||
const id = params.id;
|
||||
const id = parseId(params.id);
|
||||
|
||||
const thread = useThreadFeed(id);
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { bech32 } from "bech32";
|
||||
|
||||
import { setPrivateKey, setPublicKey } from "../state/Login";
|
||||
import { EmailRegex } from "../Const";
|
||||
import { bech32ToHex } from "../Util";
|
||||
|
||||
export default function LoginPage() {
|
||||
const dispatch = useDispatch();
|
||||
@ -20,12 +21,6 @@ export default function LoginPage() {
|
||||
}
|
||||
}, [publicKey]);
|
||||
|
||||
function bech32ToHex(str) {
|
||||
let nKey = bech32.decode(str);
|
||||
let buff = bech32.fromWords(nKey.words);
|
||||
return secp.utils.bytesToHex(Uint8Array.from(buff));
|
||||
}
|
||||
|
||||
async function getNip05PubKey(addr) {
|
||||
let [username, domain] = addr.split("@");
|
||||
let rsp = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username)}`);
|
||||
|
@ -15,14 +15,14 @@ import Modal from "../element/Modal";
|
||||
import { logout } from "../state/Login";
|
||||
import FollowButton from "../element/FollowButton";
|
||||
import VoidUpload from "../feed/VoidUpload";
|
||||
import { openFile } from "../Util";
|
||||
import { openFile, parseId } from "../Util";
|
||||
import Timeline from "../element/Timeline";
|
||||
import { extractLinks } from '../Text'
|
||||
|
||||
export default function ProfilePage() {
|
||||
const dispatch = useDispatch();
|
||||
const params = useParams();
|
||||
const id = params.id;
|
||||
const id = parseId(params.id);
|
||||
const user = useProfile(id);
|
||||
const publisher = useEventPublisher();
|
||||
const loginPubKey = useSelector(s => s.login.publicKey);
|
||||
|
Loading…
Reference in New Issue
Block a user