diff --git a/packages/app/src/Element/NostrLink.tsx b/packages/app/src/Element/NostrLink.tsx index 1b140782..bf78a541 100644 --- a/packages/app/src/Element/NostrLink.tsx +++ b/packages/app/src/Element/NostrLink.tsx @@ -2,10 +2,8 @@ import { Link } from "react-router-dom"; import { EventKind, NostrPrefix } from "@snort/nostr"; import Mention from "Element/Mention"; -import NostrFileHeader from "Element/NostrFileHeader"; import { parseNostrLink } from "Util"; import NoteQuote from "Element/NoteQuote"; -import ZapstrEmbed from "Element/ZapstrEmbed"; export default function NostrLink({ link, depth }: { link: string; depth?: number }) { const nav = parseNostrLink(link); @@ -13,13 +11,6 @@ export default function NostrLink({ link, depth }: { link: string; depth?: numbe if (nav?.type === NostrPrefix.PublicKey || nav?.type === NostrPrefix.Profile) { return ; } else if (nav?.type === NostrPrefix.Note || nav?.type === NostrPrefix.Event || nav?.type === NostrPrefix.Address) { - if (nav.kind === EventKind.FileHeader) { - return ; - } - if (nav.kind === 31337) { - return ; - } - if ((depth ?? 0) > 0) { const evLink = nav.encode(); return ( diff --git a/packages/app/src/Element/Note.tsx b/packages/app/src/Element/Note.tsx index 42cfd4cb..889f453c 100644 --- a/packages/app/src/Element/Note.tsx +++ b/packages/app/src/Element/Note.tsx @@ -30,6 +30,7 @@ import { EventExt } from "System/EventExt"; import useLogin from "Hooks/useLogin"; import { setBookmarked, setPinned } from "Login"; import { NostrFileElement } from "Element/NostrFileHeader"; +import ZapstrEmbed from "Element/ZapstrEmbed"; import messages from "./messages"; @@ -78,7 +79,9 @@ export default function Note(props: NoteProps) { if (ev.kind === EventKind.FileHeader) { return ; } - + if (ev.kind === 31337) { + return ; + } const navigate = useNavigate(); const [showReactions, setShowReactions] = useState(false); const deletions = useMemo(() => getReactions(related, ev.id, EventKind.Deletion), [related]); diff --git a/packages/app/src/Element/NoteCreator.tsx b/packages/app/src/Element/NoteCreator.tsx index fd65f20c..b1e5f59d 100644 --- a/packages/app/src/Element/NoteCreator.tsx +++ b/packages/app/src/Element/NoteCreator.tsx @@ -142,7 +142,7 @@ export function NoteCreator() { if (file) { const rx = await uploader.upload(file, file.name); if (rx.header) { - const link = `nostr:${encodeTLV(rx.header.id, NostrPrefix.Event, undefined, rx.header.kind)}`; + const link = `nostr:${encodeTLV(NostrPrefix.Event, rx.header.id, undefined, rx.header.kind)}`; dispatch(setNote(`${note ? `${note}\n` : ""}${link}`)); dispatch(setOtherEvents([...otherEvents, rx.header])); } else if (rx.url) { diff --git a/packages/app/src/Element/NoteFooter.tsx b/packages/app/src/Element/NoteFooter.tsx index 50cdc9bb..a9f523c4 100644 --- a/packages/app/src/Element/NoteFooter.tsx +++ b/packages/app/src/Element/NoteFooter.tsx @@ -264,7 +264,7 @@ export default function NoteFooter(props: NoteFooterProps) { } async function share() { - const link = encodeTLV(ev.id, NostrPrefix.Event, ev.relays); + const link = encodeTLV(NostrPrefix.Event, ev.id, ev.relays); const url = `${window.location.protocol}//${window.location.host}/e/${link}`; if ("share" in window.navigator) { await window.navigator.share({ @@ -300,7 +300,7 @@ export default function NoteFooter(props: NoteFooterProps) { } async function copyId() { - const link = encodeTLV(ev.id, NostrPrefix.Event, ev.relays); + const link = encodeTLV(NostrPrefix.Event, ev.id, ev.relays); await navigator.clipboard.writeText(link); } diff --git a/packages/app/src/Element/WriteDm.tsx b/packages/app/src/Element/WriteDm.tsx index 5efc2118..eb9a25ea 100644 --- a/packages/app/src/Element/WriteDm.tsx +++ b/packages/app/src/Element/WriteDm.tsx @@ -35,7 +35,7 @@ export default function WriteDm({ chatPubKey }: { chatPubKey: string }) { if (file) { const rx = await uploader.upload(file, file.name); if (rx.header) { - const link = `nostr:${encodeTLV(rx.header.id, NostrPrefix.Event, undefined, rx.header.kind)}`; + const link = `nostr:${encodeTLV(NostrPrefix.Event, rx.header.id, undefined, rx.header.kind)}`; setMsg(`${msg ? `${msg}\n` : ""}${link}`); setOtherEvents([...otherEvents, rx.header]); } else if (rx.url) { diff --git a/packages/app/src/Element/ZapstrEmbed.tsx b/packages/app/src/Element/ZapstrEmbed.tsx index 99bde748..b8cb0e0c 100644 --- a/packages/app/src/Element/ZapstrEmbed.tsx +++ b/packages/app/src/Element/ZapstrEmbed.tsx @@ -1,25 +1,27 @@ import "./ZapstrEmbed.css"; import { Link } from "react-router-dom"; +import { encodeTLV, NostrPrefix, RawEvent } from "@snort/nostr"; -import useEventFeed from "Feed/EventFeed"; -import Spinner from "Icons/Spinner"; -import { NostrLink } from "Util"; import { ProxyImg } from "Element/ProxyImg"; import ProfileImage from "Element/ProfileImage"; import { FormattedMessage } from "react-intl"; -export default function ZapstrEmbed({ link }: { link: NostrLink }) { - const ev = useEventFeed(link); +export default function ZapstrEmbed({ ev }: { ev: RawEvent }) { + const media = ev.tags.find(a => a[0] === "media"); + const cover = ev.tags.find(a => a[0] === "cover"); + const subject = ev.tags.find(a => a[0] === "subject"); + const refPersons = ev.tags.filter(a => a[0] === "p"); - if (!ev.data) return ; - - const media = ev.data.tags.find(a => a[0] === "media"); - const cover = ev.data.tags.find(a => a[0] === "cover"); - const subject = ev.data.tags.find(a => a[0] === "subject"); - const refPersons = ev.data.tags.filter(a => a[0] === "p"); + const link = encodeTLV( + NostrPrefix.Address, + ev.tags.find(a => a[0] === "d")?.[1] ?? "", + undefined, + ev.kind, + ev.pubkey + ); return ( <> -
+
@@ -33,7 +35,7 @@ export default function ZapstrEmbed({ link }: { link: NostrLink }) {
- + diff --git a/packages/app/src/Pages/ProfilePage.tsx b/packages/app/src/Pages/ProfilePage.tsx index efebae61..5ed1c59f 100644 --- a/packages/app/src/Pages/ProfilePage.tsx +++ b/packages/app/src/Pages/ProfilePage.tsx @@ -296,7 +296,7 @@ export default function ProfilePage() { function renderIcons() { if (!id) return; - const link = encodeTLV(id, NostrPrefix.Profile); + const link = encodeTLV(NostrPrefix.Profile, id); return (
setShowProfileQr(true)}> diff --git a/packages/app/src/Pages/settings/Keys.tsx b/packages/app/src/Pages/settings/Keys.tsx index 1fafd927..e5220cf1 100644 --- a/packages/app/src/Pages/settings/Keys.tsx +++ b/packages/app/src/Pages/settings/Keys.tsx @@ -15,7 +15,7 @@ export default function ExportKeys() { - + {privateKey && ( <>

diff --git a/packages/app/src/Util.ts b/packages/app/src/Util.ts index 19b70110..d8d2eab4 100644 --- a/packages/app/src/Util.ts +++ b/packages/app/src/Util.ts @@ -91,7 +91,7 @@ export function bech32ToText(str: string) { */ export function eventLink(hex: u256, relays?: Array | string) { const encoded = relays - ? encodeTLV(hex, NostrPrefix.Event, Array.isArray(relays) ? relays : [relays]) + ? encodeTLV(NostrPrefix.Event, hex, Array.isArray(relays) ? relays : [relays]) : hexToBech32(NostrPrefix.Note, hex); return `/e/${encoded}`; } @@ -101,7 +101,7 @@ export function eventLink(hex: u256, relays?: Array | string) { */ export function profileLink(hex: HexKey, relays?: Array | string) { const encoded = relays - ? encodeTLV(hex, NostrPrefix.Profile, Array.isArray(relays) ? relays : [relays]) + ? encodeTLV(NostrPrefix.Event, hex, Array.isArray(relays) ? relays : [relays]) : hexToBech32(NostrPrefix.PublicKey, hex); return `/p/${encoded}`; } @@ -119,7 +119,7 @@ export function hexToBech32(hrp: string, hex?: string) { const buf = secp.utils.hexToBytes(hex); return bech32.encode(hrp, bech32.toWords(buf)); } else { - return encodeTLV(hex, hrp as NostrPrefix); + return encodeTLV(hrp as NostrPrefix, hex); } } catch (e) { console.warn("Invalid hex", hex, e); diff --git a/packages/nostr/src/legacy/Links.ts b/packages/nostr/src/legacy/Links.ts index c21763ae..70071328 100644 --- a/packages/nostr/src/legacy/Links.ts +++ b/packages/nostr/src/legacy/Links.ts @@ -27,13 +27,9 @@ export interface TLVEntry { value: string | HexKey | number; } -export function encodeTLV(hex: string, prefix: NostrPrefix, relays?: string[], kind?: number) { - if (typeof hex !== "string" || hex.length === 0 || hex.length % 2 !== 0) { - return ""; - } - +export function encodeTLV(prefix: NostrPrefix, id: string, relays?: string[], kind?: number, author?: string) { const enc = new TextEncoder(); - const buf = secp.utils.hexToBytes(hex); + const buf = prefix === NostrPrefix.Address ? enc.encode(id) : secp.utils.hexToBytes(id); const tl0 = [0, buf.length, ...buf]; const tl1 = @@ -43,9 +39,11 @@ export function encodeTLV(hex: string, prefix: NostrPrefix, relays?: string[], k return [1, data.length, ...data]; }) .flat() ?? []; + + const tl2 = author ? [2, 32, ...secp.utils.hexToBytes(author)] : []; const tl3 = kind ? [3, 4, ...new Uint8Array(new Uint32Array([kind]).buffer).reverse()] : [] - return bech32.encode(prefix, bech32.toWords([...tl0, ...tl1, ...tl3]), 1_000); + return bech32.encode(prefix, bech32.toWords([...tl0, ...tl1, ...tl2, ...tl3]), 1_000); } export function decodeTLV(str: string) {