From 3b6815310550f219ab65eb58801e810f41d51f27 Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 16 Feb 2023 16:32:56 +0000 Subject: [PATCH] bug: redirect tlv entry --- packages/app/src/Pages/NostrLinkHandler.tsx | 34 +++++++++++++++++---- packages/app/src/Util.ts | 2 +- packages/nostr/src/legacy/Links.ts | 31 ++++++++++++++++--- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/packages/app/src/Pages/NostrLinkHandler.tsx b/packages/app/src/Pages/NostrLinkHandler.tsx index 9721d4c..b61e5f5 100644 --- a/packages/app/src/Pages/NostrLinkHandler.tsx +++ b/packages/app/src/Pages/NostrLinkHandler.tsx @@ -1,20 +1,42 @@ -import { NostrPrefix } from "@snort/nostr"; +import { decodeTLV, NostrPrefix, TLVEntryType } from "@snort/nostr"; import { useEffect } from "react"; +import { useDispatch } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; +import { setRelays } from "State/Login"; +import { eventLink, profileLink } from "Util"; export default function NostrLinkHandler() { const params = useParams(); + const dispatch = useDispatch(); const navigate = useNavigate(); - const link = decodeURIComponent(params["*"] ?? ""); + const link = decodeURIComponent(params["*"] ?? "").toLowerCase(); useEffect(() => { if (link.length > 0) { - const ls = link.split(":"); - const entity = ls[1]; - if (entity.startsWith(NostrPrefix.PublicKey) || entity.startsWith(NostrPrefix.Profile)) { + const entity = link.startsWith("web+nostr:") ? link.split(":")[1] : link; + if (entity.startsWith(NostrPrefix.PublicKey)) { navigate(`/p/${entity}`); - } else if (entity.startsWith(NostrPrefix.Event) || entity.startsWith(NostrPrefix.Note)) { + } else if (entity.startsWith(NostrPrefix.Note)) { navigate(`/e/${entity}`); + } else if (entity.startsWith(NostrPrefix.Profile) || entity.startsWith(NostrPrefix.Event)) { + const decoded = decodeTLV(entity); + console.debug(decoded); + + const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string; + const relays = decoded.filter(a => a.type === TLVEntryType.Relay); + if (relays.length > 0) { + const relayObj = { + relays: Object.fromEntries(relays.map(a => [a.value, { read: true, write: false }])), + createdAt: new Date().getTime(), + }; + dispatch(setRelays(relayObj)); + } + + if (entity.startsWith(NostrPrefix.Profile)) { + navigate(profileLink(id)); + } else if (entity.startsWith(NostrPrefix.Event)) { + navigate(eventLink(id)); + } } } }, [link]); diff --git a/packages/app/src/Util.ts b/packages/app/src/Util.ts index 8625f7d..7456ee5 100644 --- a/packages/app/src/Util.ts +++ b/packages/app/src/Util.ts @@ -41,7 +41,7 @@ export function parseId(id: string) { } export function bech32ToHex(str: string) { - const nKey = bech32.decode(str); + const nKey = bech32.decode(str, 1_000); const buff = bech32.fromWords(nKey.words); return secp.utils.bytesToHex(Uint8Array.from(buff)); } diff --git a/packages/nostr/src/legacy/Links.ts b/packages/nostr/src/legacy/Links.ts index 72bc5bb..4b5a0d9 100644 --- a/packages/nostr/src/legacy/Links.ts +++ b/packages/nostr/src/legacy/Links.ts @@ -1,5 +1,6 @@ import * as secp from "@noble/secp256k1"; import { bech32 } from "bech32"; +import { HexKey } from "."; export enum NostrPrefix { PublicKey = "npub", @@ -12,10 +13,17 @@ export enum NostrPrefix { Relay = "nrelay", } +export enum TLVEntryType { + Special = 0, + Relay = 1, + Author = 2, + Kind = 3, +} + export interface TLVEntry { - type: number; + type: TLVEntryType; length: number; - value: string; // hex encoded data + value: string | HexKey | number; } export function encodeTLV(hex: string, prefix: NostrPrefix, relays?: string[]) { @@ -39,7 +47,7 @@ export function encodeTLV(hex: string, prefix: NostrPrefix, relays?: string[]) { } export function decodeTLV(str: string) { - const decoded = bech32.decode(str); + const decoded = bech32.decode(str, 1_000); const data = bech32.fromWords(decoded.words); const entries: TLVEntry[] = []; @@ -51,9 +59,24 @@ export function decodeTLV(str: string) { entries.push({ type: t, length: l, - value: secp.utils.bytesToHex(new Uint8Array(v)), + value: decodeTLVEntry(t, new Uint8Array(v)), }); x += 2 + l; } return entries; } + +function decodeTLVEntry(type: TLVEntryType, data: Uint8Array) { + switch (type) { + case TLVEntryType.Special: + case TLVEntryType.Author: { + return secp.utils.bytesToHex(data); + } + case TLVEntryType.Kind: { + return 0 + } + case TLVEntryType.Relay: { + return new TextDecoder("ASCII").decode(data); + } + } +}