From f3d203294482aa978f972c3b42ed02b25c2a124f Mon Sep 17 00:00:00 2001 From: Simone <185146821+Lucenx9@users.noreply.github.com> Date: Thu, 13 Aug 2026 18:17:28 +0200 Subject: [PATCH] fix(mobile): prevent invalid HTML entities from crashing markdown --- .../t3-markdown-text/src/nativeMarkdownText.ts | 11 +++++++++-- apps/mobile/src/lib/nativeMarkdownText.test.ts | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts b/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts index dc84755cbbd7..47105fb7714b 100644 --- a/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts +++ b/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts @@ -70,15 +70,22 @@ const EMPTY_CONTEXT: RunContext = { const INLINE_HTML_TAG_PATTERN = /<\/?(?:kbd|mark|sub|sup|u)(?:\s[^>]*)?>/gi; +function decodeCodePoint(codePoint: number, entity: string): string { + if (!Number.isInteger(codePoint) || codePoint < 0 || codePoint > 0x10ffff) { + return entity; + } + return String.fromCodePoint(codePoint); +} + function decodeHtmlEntitiesOnce(value: string): string { return value.replace( /&(?:#(\d+)|#x([0-9a-f]+)|amp|apos|gt|lt|nbsp|quot);/gi, (entity, decimal: string | undefined, hexadecimal: string | undefined) => { if (decimal) { - return String.fromCodePoint(Number.parseInt(decimal, 10)); + return decodeCodePoint(Number.parseInt(decimal, 10), entity); } if (hexadecimal) { - return String.fromCodePoint(Number.parseInt(hexadecimal, 16)); + return decodeCodePoint(Number.parseInt(hexadecimal, 16), entity); } switch (entity.toLowerCase()) { case "&": diff --git a/apps/mobile/src/lib/nativeMarkdownText.test.ts b/apps/mobile/src/lib/nativeMarkdownText.test.ts index 6e41f2243a93..ea1db30c489d 100644 --- a/apps/mobile/src/lib/nativeMarkdownText.test.ts +++ b/apps/mobile/src/lib/nativeMarkdownText.test.ts @@ -126,6 +126,22 @@ describe("nativeMarkdownTextRuns", () => { ]); }); + it.each([ + ["😀", "😀"], + ["🚀", "🚀"], + ["�", "�"], + ["�", "�"], + ["&#9999999999;", "�"], + ["&#x110000;", "�"], + ])("normalizes numeric entity %s without throwing", (content, expected) => { + const node: MarkdownNode = { + type: "paragraph", + children: [{ type: "text", content }], + }; + + expect(nativeMarkdownTextRuns(node)).toEqual([{ text: expected }]); + }); + it("reads inline content from nested text nodes", () => { const node: MarkdownNode = { type: "paragraph",