From 8d8211de090534d1f3f71825760c9f5866f6d4bd Mon Sep 17 00:00:00 2001 From: danidfra Date: Wed, 28 Aug 2024 14:01:26 -0300 Subject: [PATCH 1/3] Fixed apostrophe issue --- src/utils/note.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/note.ts b/src/utils/note.ts index 00be4b1a..aba3d041 100644 --- a/src/utils/note.ts +++ b/src/utils/note.ts @@ -23,7 +23,6 @@ interface ParsedNoteContent { function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedNoteContent { const links = linkify.find(content).filter(isLinkURL); const firstUrl = links.find(isNonMediaLink)?.href; - const html = linkifyStr(content, { render: { hashtag: ({ content }) => { @@ -32,6 +31,8 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN return `#${tag}`; }, url: ({ attributes, content }) => { + const extra = content.slice(69) + content = content.slice(0,69) try { const { decoded } = nip21.parse(content); const pubkey = getDecodedPubkey(decoded); @@ -41,7 +42,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN const acct = mention?.acct ?? npub; const name = mention?.acct ?? npub.substring(0, 8); const href = mention?.url ?? Conf.local(`/@${acct}`); - return `@${name}`; + return `@${name}${extra}`; } else { return ''; } From c2ea4cbfd5a124f430151a017b007ea845035bc9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 28 Aug 2024 19:33:22 +0200 Subject: [PATCH 2/3] Fix parsing bech32 with apostrophe --- src/utils/note.test.ts | 21 +++++++++++++++++++++ src/utils/note.ts | 39 ++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/utils/note.test.ts b/src/utils/note.test.ts index 0c9c6bf8..67f802c6 100644 --- a/src/utils/note.test.ts +++ b/src/utils/note.test.ts @@ -10,6 +10,27 @@ Deno.test('parseNoteContent', () => { assertEquals(firstUrl, undefined); }); +Deno.test('parseNoteContent handles apostrophes', () => { + const { html } = parseNoteContent( + `did you see nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgprdmhxue69uhkwmr9v9ek7mnpw3hhytnyv4mz7un9d3shjqgcwaehxw309ahx7umywf5hvefwv9c8qtmjv4kxz7gpzemhxue69uhhyetvv9ujumt0wd68ytnsw43z7s3al0v's speech?`, + [{ + id: '0461fcbecc4c3374439932d6b8f11269ccdb7cc973ad7a50ae362db135a474dd', + username: 'alex', + acct: 'alex@gleasonator.dev', + url: 'https://gleasonator.dev/@alex', + }], + ); + assertEquals( + html, + `did you see @alex@gleasonator.dev's speech?`, + ); +}); + +Deno.test("parseNoteContent doesn't parse invalid nostr URIs", () => { + const { html } = parseNoteContent(`nip19 has URIs like nostr:npub and nostr:nevent, etc.`, []); + assertEquals(html, 'nip19 has URIs like nostr:npub and nostr:nevent, etc.'); +}); + Deno.test('getMediaLinks', () => { const links = [ { href: 'https://example.com/image.png' }, diff --git a/src/utils/note.ts b/src/utils/note.ts index aba3d041..da5197d5 100644 --- a/src/utils/note.ts +++ b/src/utils/note.ts @@ -1,10 +1,11 @@ import 'linkify-plugin-hashtag'; import linkifyStr from 'linkify-string'; import linkify from 'linkifyjs'; -import { nip19, nip21, nip27 } from 'nostr-tools'; +import { nip19, nip27 } from 'nostr-tools'; import { Conf } from '@/config.ts'; import { MastodonMention } from '@/entities/MastodonMention.ts'; +import { html } from '@/utils/html.ts'; import { getUrlMediaType, isPermittedMediaType } from '@/utils/media.ts'; linkify.registerCustomProtocol('nostr', true); @@ -23,29 +24,33 @@ interface ParsedNoteContent { function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedNoteContent { const links = linkify.find(content).filter(isLinkURL); const firstUrl = links.find(isNonMediaLink)?.href; - const html = linkifyStr(content, { + + const result = linkifyStr(content, { render: { hashtag: ({ content }) => { const tag = content.replace(/^#/, ''); const href = Conf.local(`/tags/${tag}`); - return `#${tag}`; + return html`#${tag}`; }, url: ({ attributes, content }) => { - const extra = content.slice(69) - content = content.slice(0,69) try { - const { decoded } = nip21.parse(content); - const pubkey = getDecodedPubkey(decoded); - if (pubkey) { - const mention = mentions.find((m) => m.id === pubkey); - const npub = nip19.npubEncode(pubkey); - const acct = mention?.acct ?? npub; - const name = mention?.acct ?? npub.substring(0, 8); - const href = mention?.url ?? Conf.local(`/@${acct}`); - return `@${name}${extra}`; - } else { - return ''; + const { pathname } = new URL(content); + const match = pathname.match(new RegExp(`^${nip19.BECH32_REGEX.source}`)); + if (match) { + const bech32 = match[0]; + const extra = pathname.slice(bech32.length); + const decoded = nip19.decode(bech32); + const pubkey = getDecodedPubkey(decoded); + if (pubkey) { + const mention = mentions.find((m) => m.id === pubkey); + const npub = nip19.npubEncode(pubkey); + const acct = mention?.acct ?? npub; + const name = mention?.acct ?? npub.substring(0, 8); + const href = mention?.url ?? Conf.local(`/@${acct}`); + return html`@${name}${extra}`; + } } + return content; } catch { const attr = Object.entries(attributes) .map(([name, value]) => `${name}="${value}"`) @@ -58,7 +63,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN }).replace(/\n+$/, ''); return { - html, + html: result, links, firstUrl, }; From f9d1eed4dd86ae3fe4ced018b163ee49b963673d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 28 Aug 2024 19:46:19 +0200 Subject: [PATCH 3/3] Remove unnecessary escape characters --- src/utils/note.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/note.ts b/src/utils/note.ts index da5197d5..8a47937a 100644 --- a/src/utils/note.ts +++ b/src/utils/note.ts @@ -30,7 +30,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN hashtag: ({ content }) => { const tag = content.replace(/^#/, ''); const href = Conf.local(`/tags/${tag}`); - return html`#${tag}`; + return html``; }, url: ({ attributes, content }) => { try {