Skip to content

Commit 0e77485

Browse files
authored
Escape JSON LD content in <Meta /> (#14316)
1 parent 8099681 commit 0e77485

File tree

7 files changed

+15
-33
lines changed

7 files changed

+15
-33
lines changed

.changeset/angry-planets-admire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Escape HTML in `meta()` JSON-LD content

packages/react-router/__tests__/dom/ssr/meta-test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ describe("meta", () => {
251251
postalCode: "92107",
252252
},
253253
254+
bio: "A <b>surfer</b> & <em>coder</em>.",
254255
};
255256

256257
let RoutesStub = createRoutesStub([
@@ -273,6 +274,9 @@ describe("meta", () => {
273274
container.querySelector('script[type="application/ld+json"]')
274275
?.innerHTML || "{}";
275276
expect(JSON.parse(scriptTagContents)).toEqual(jsonLd);
277+
expect(scriptTagContents).toContain(
278+
"A \\u003cb\\u003esurfer\\u003c/b\\u003e \\u0026 \\u003cem\\u003ecoder\\u003c/em\\u003e.",
279+
);
276280
});
277281

278282
it("{ tagName: 'link' } adds a <link />", () => {

packages/react-router/__tests__/server-runtime/markup-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import vm from "vm";
22

3-
import { escapeHtml } from "../../lib/server-runtime/markup";
3+
import { escapeHtml } from "../../lib/dom/ssr/markup";
44

55
describe("escapeHtml", () => {
66
// These tests are based on https://github.com/zertosh/htmlescape/blob/3e6cf0614dd0f778fd0131e69070b77282150c15/test/htmlescape-test.js

packages/react-router/lib/dom/ssr/components.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
isPageLinkDescriptor,
2020
} from "./links";
2121
import type { KeyedHtmlLinkDescriptor } from "./links";
22-
import { createHtml } from "./markup";
22+
import { escapeHtml } from "./markup";
2323
import type {
2424
MetaFunction,
2525
MetaDescriptor,
@@ -629,7 +629,7 @@ export function Meta(): React.JSX.Element {
629629
<script
630630
key={`script:ld+json:${json}`}
631631
type="application/ld+json"
632-
dangerouslySetInnerHTML={{ __html: json }}
632+
dangerouslySetInnerHTML={{ __html: escapeHtml(json) }}
633633
/>
634634
);
635635
} catch (err) {
@@ -860,13 +860,13 @@ import(${JSON.stringify(manifest.entry.module)});`;
860860
<script
861861
{...scriptProps}
862862
suppressHydrationWarning
863-
dangerouslySetInnerHTML={createHtml(contextScript)}
863+
dangerouslySetInnerHTML={{ __html: contextScript }}
864864
type={undefined}
865865
/>
866866
<script
867867
{...scriptProps}
868868
suppressHydrationWarning
869-
dangerouslySetInnerHTML={createHtml(routeModulesScript)}
869+
dangerouslySetInnerHTML={{ __html: routeModulesScript }}
870870
type="module"
871871
async
872872
/>

packages/react-router/lib/dom/ssr/markup.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,3 @@ const ESCAPE_REGEX = /[&><\u2028\u2029]/g;
1717
export function escapeHtml(html: string) {
1818
return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
1919
}
20-
21-
export interface SafeHtml {
22-
__html: string;
23-
}
24-
25-
export function createHtml(html: string): SafeHtml {
26-
return { __html: html };
27-
}

packages/react-router/lib/server-runtime/markup.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

packages/react-router/lib/server-runtime/serverHandoff.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { CriticalCss, FutureConfig } from "../dom/ssr/entry";
2-
import { escapeHtml } from "./markup";
2+
import { escapeHtml } from "../dom/ssr/markup";
33
import type { ServerBuild } from "./build";
44

55
export type ServerHandoff = {

0 commit comments

Comments
 (0)