Skip to content

Commit f2f38f7

Browse files
sserratablindaa121
andauthored
[Bug] Implement selective escape for sanitizing titles and descriptions (#301)
* Selective escape only non-HTML tags * Update lookbehinds * Expand regex patterns * Extend HTML support for ParamsItem and SchemaItem components via rehypeRaw plugin * Move greaterThan and lessThan to utils and refactor createDescription * Add button to regex Co-authored-by: Bryan <[email protected]>
1 parent 3a5a008 commit f2f38f7

File tree

7 files changed

+139
-9
lines changed

7 files changed

+139
-9
lines changed

packages/docusaurus-plugin-openapi-docs/src/markdown/createDescription.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8+
import { greaterThan, lessThan } from "./utils";
9+
810
export function createDescription(description: string | undefined) {
911
if (!description) {
1012
return "";
1113
}
12-
return `\n\n${description}\n\n`;
14+
return `\n\n${description
15+
.replace(lessThan, "&lt;")
16+
.replace(greaterThan, "&gt;")}\n\n`;
1317
}

packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import { escape } from "lodash";
9-
108
import {
119
ContactObject,
1210
LicenseObject,
@@ -25,7 +23,7 @@ import { createRequestBodyDetails } from "./createRequestBodyDetails";
2523
import { createStatusCodes } from "./createStatusCodes";
2624
import { createTermsOfService } from "./createTermsOfService";
2725
import { createVersionBadge } from "./createVersionBadge";
28-
import { render } from "./utils";
26+
import { greaterThan, lessThan, render } from "./utils";
2927

3028
interface Props {
3129
title: string;
@@ -58,9 +56,9 @@ export function createApiPageMD({
5856
`import SchemaTabs from "@theme/SchemaTabs";\n`,
5957
`import DiscriminatorTabs from "@theme/DiscriminatorTabs";\n`,
6058
`import TabItem from "@theme/TabItem";\n\n`,
61-
`## ${escape(title)}\n\n`,
59+
`## ${title.replace(lessThan, "&lt;").replace(greaterThan, "&gt;")}\n\n`,
6260
createDeprecationNotice({ deprecated, description: deprecatedDescription }),
63-
createDescription(escape(description)),
61+
createDescription(description),
6462
createParamsDetails({ parameters, type: "path" }),
6563
createParamsDetails({ parameters, type: "query" }),
6664
createParamsDetails({ parameters, type: "header" }),
@@ -92,7 +90,7 @@ export function createInfoPageMD({
9290
`import TabItem from "@theme/TabItem";\n\n`,
9391

9492
createVersionBadge(version),
95-
`# ${escape(title)}\n\n`,
93+
`# ${title.replace(lessThan, "&lt;").replace(greaterThan, "&gt;")}\n\n`,
9694
createLogo(logo, darkLogo),
9795
createDescription(description),
9896
createAuthentication(securitySchemes as unknown as SecuritySchemeObject),

packages/docusaurus-plugin-openapi-docs/src/markdown/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,9 @@ export function render(children: Children): string {
4040
}
4141
return children ?? "";
4242
}
43+
44+
// Regex to selectively URL-encode '>' and '<' chars
45+
export const lessThan =
46+
/<(?!(button|\s?\/button|details|\s?\/details|summary|\s?\/summary|hr|\s?\/hr|br|\s?\/br|span|\s?\/span|strong|\s?\/strong|small|\s?\/small|table|\s?\/table|td|\s?\/td|tr|\s?\/tr|th|\s?\/th|h1|\s?\/h1|h2|\s?\/h2|h3|\s?\/h3|h4|\s?\/h4|h5|\s?\/h5|h6|\s?\/h6|title|\s?\/title|p|\s?\/p|em|\s?\/em|b|\s?\/b|i|\s?\/i|u|\s?\/u|strike|\s?\/strike|a|\s?\/a|li|\s?\/li|ol|\s?\/ol|ul|\s?\/ul|img|\s?\/img|div|\s?\/div|center|\s?\/center))/giu;
47+
export const greaterThan =
48+
/(?<!(button|details|summary|hr|br|span|strong|small|table|td|tr|th|h1|h2|h3|h4|h5|h6|title|p|em|b|i|u|strike|a|tag|li|ol|ul|img|div|center|\/|\s|"|'))>/giu;

packages/docusaurus-theme-openapi-docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"react-modal": "^3.15.1",
6161
"react-redux": "^7.2.0",
6262
"redux-devtools-extension": "^2.13.8",
63+
"rehype-raw": "^6.1.1",
6364
"webpack": "^5.61.0",
6465
"xml-formatter": "^2.6.1"
6566
},

packages/docusaurus-theme-openapi-docs/src/theme/ParamsItem/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import React from "react";
99

1010
import CodeBlock from "@theme/CodeBlock";
1111
import ReactMarkdown from "react-markdown";
12+
import rehypeRaw from "rehype-raw";
1213

1314
import { createDescription } from "../../markdown/createDescription";
1415
import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
@@ -28,7 +29,10 @@ function ParamsItem({
2829

2930
const renderSchema = guard(getQualifierMessage(schema), (message) => (
3031
<div>
31-
<ReactMarkdown children={createDescription(message)} />
32+
<ReactMarkdown
33+
children={createDescription(message)}
34+
rehypePlugins={[rehypeRaw]}
35+
/>
3236
</div>
3337
));
3438

@@ -48,6 +52,7 @@ function ParamsItem({
4852
);
4953
},
5054
}}
55+
rehypePlugins={[rehypeRaw]}
5156
/>
5257
</div>
5358
));

packages/docusaurus-theme-openapi-docs/src/theme/SchemaItem/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import React from "react";
99

1010
import CodeBlock from "@theme/CodeBlock";
1111
import ReactMarkdown from "react-markdown";
12+
import rehypeRaw from "rehype-raw";
1213

1314
import { createDescription } from "../../markdown/createDescription";
1415
import { guard } from "../../markdown/utils";
@@ -45,13 +46,17 @@ function SchemaItem({
4546
);
4647
},
4748
}}
49+
rehypePlugins={[rehypeRaw]}
4850
/>
4951
</div>
5052
));
5153

5254
const renderQualifierMessage = guard(qualifierMessage, (message) => (
5355
<div className={styles.schemaQualifierMessage}>
54-
<ReactMarkdown children={createDescription(message)} />
56+
<ReactMarkdown
57+
children={createDescription(message)}
58+
rehypePlugins={[rehypeRaw]}
59+
/>
5560
</div>
5661
));
5762

yarn.lock

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4180,6 +4180,11 @@
41804180
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
41814181
integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==
41824182

4183+
"@types/parse5@^6.0.0":
4184+
version "6.0.3"
4185+
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb"
4186+
integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
4187+
41834188
"@types/prettier@^2.1.5":
41844189
version "2.6.3"
41854190
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a"
@@ -8434,6 +8439,19 @@ has@^1.0.3:
84348439
dependencies:
84358440
function-bind "^1.1.1"
84368441

8442+
hast-to-hyperscript@^10.0.0:
8443+
version "10.0.1"
8444+
resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-10.0.1.tgz#3decd7cb4654bca8883f6fcbd4fb3695628c4296"
8445+
integrity sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==
8446+
dependencies:
8447+
"@types/unist" "^2.0.0"
8448+
comma-separated-tokens "^2.0.0"
8449+
property-information "^6.0.0"
8450+
space-separated-tokens "^2.0.0"
8451+
style-to-object "^0.3.0"
8452+
unist-util-is "^5.0.0"
8453+
web-namespaces "^2.0.0"
8454+
84378455
hast-to-hyperscript@^9.0.0:
84388456
version "9.0.1"
84398457
resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d"
@@ -8459,11 +8477,32 @@ hast-util-from-parse5@^6.0.0:
84598477
vfile-location "^3.2.0"
84608478
web-namespaces "^1.0.0"
84618479

8480+
hast-util-from-parse5@^7.0.0:
8481+
version "7.1.0"
8482+
resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-7.1.0.tgz#c129dd3a24dd8a867ab8a029ca47e27aa54864b7"
8483+
integrity sha512-m8yhANIAccpU4K6+121KpPP55sSl9/samzQSQGpb0mTExcNh2WlvjtMwSWFhg6uqD4Rr6Nfa8N6TMypQM51rzQ==
8484+
dependencies:
8485+
"@types/hast" "^2.0.0"
8486+
"@types/parse5" "^6.0.0"
8487+
"@types/unist" "^2.0.0"
8488+
hastscript "^7.0.0"
8489+
property-information "^6.0.0"
8490+
vfile "^5.0.0"
8491+
vfile-location "^4.0.0"
8492+
web-namespaces "^2.0.0"
8493+
84628494
hast-util-parse-selector@^2.0.0:
84638495
version "2.2.5"
84648496
resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a"
84658497
integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==
84668498

8499+
hast-util-parse-selector@^3.0.0:
8500+
version "3.1.0"
8501+
resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-3.1.0.tgz#a519e27e8b61bd5a98fad494ed06131ce68d9c3f"
8502+
integrity sha512-AyjlI2pTAZEOeu7GeBPZhROx0RHBnydkQIXlhnFzDi0qfXTmGUWoCYZtomHbrdrheV4VFUlPcfJ6LMF5T6sQzg==
8503+
dependencies:
8504+
"@types/hast" "^2.0.0"
8505+
84678506
84688507
version "6.0.1"
84698508
resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977"
@@ -8480,6 +8519,23 @@ [email protected]:
84808519
xtend "^4.0.0"
84818520
zwitch "^1.0.0"
84828521

8522+
hast-util-raw@^7.2.0:
8523+
version "7.2.2"
8524+
resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-7.2.2.tgz#1974360b2d7f15b5ce26c2a4bac892d5d8185a18"
8525+
integrity sha512-0x3BhhdlBcqRIKyc095lBSDvmQNMY3Eulj2PLsT5XCyKYrxssI5yr3P4Kv/PBo1s/DMkZy2voGkMXECnFCZRLQ==
8526+
dependencies:
8527+
"@types/hast" "^2.0.0"
8528+
"@types/parse5" "^6.0.0"
8529+
hast-util-from-parse5 "^7.0.0"
8530+
hast-util-to-parse5 "^7.0.0"
8531+
html-void-elements "^2.0.0"
8532+
parse5 "^6.0.0"
8533+
unist-util-position "^4.0.0"
8534+
unist-util-visit "^4.0.0"
8535+
vfile "^5.0.0"
8536+
web-namespaces "^2.0.0"
8537+
zwitch "^2.0.0"
8538+
84838539
hast-util-to-parse5@^6.0.0:
84848540
version "6.0.0"
84858541
resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479"
@@ -8491,6 +8547,18 @@ hast-util-to-parse5@^6.0.0:
84918547
xtend "^4.0.0"
84928548
zwitch "^1.0.0"
84938549

8550+
hast-util-to-parse5@^7.0.0:
8551+
version "7.0.0"
8552+
resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-7.0.0.tgz#a39808e69005d10afeed1866029a1fb137df3f7c"
8553+
integrity sha512-YHiS6aTaZ3N0Q3nxaY/Tj98D6kM8QX5Q8xqgg8G45zR7PvWnPGPP0vcKCgb/moIydEJ/QWczVrX0JODCVeoV7A==
8554+
dependencies:
8555+
"@types/hast" "^2.0.0"
8556+
"@types/parse5" "^6.0.0"
8557+
hast-to-hyperscript "^10.0.0"
8558+
property-information "^6.0.0"
8559+
web-namespaces "^2.0.0"
8560+
zwitch "^2.0.0"
8561+
84948562
hast-util-whitespace@^2.0.0:
84958563
version "2.0.0"
84968564
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c"
@@ -8507,6 +8575,17 @@ hastscript@^6.0.0:
85078575
property-information "^5.0.0"
85088576
space-separated-tokens "^1.0.0"
85098577

8578+
hastscript@^7.0.0:
8579+
version "7.1.0"
8580+
resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-7.1.0.tgz#e402ed48f46161cf2f093badbff30583a5c3c315"
8581+
integrity sha512-uBjaTTLN0MkCZxY/R2fWUOcu7FRtUVzKRO5P/RAfgsu3yFiMB1JWCO4AjeVkgHxAira1f2UecHK5WfS9QurlWA==
8582+
dependencies:
8583+
"@types/hast" "^2.0.0"
8584+
comma-separated-tokens "^2.0.0"
8585+
hast-util-parse-selector "^3.0.0"
8586+
property-information "^6.0.0"
8587+
space-separated-tokens "^2.0.0"
8588+
85108589
he@^1.2.0:
85118590
version "1.2.0"
85128591
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -8612,6 +8691,11 @@ html-void-elements@^1.0.0:
86128691
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483"
86138692
integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==
86148693

8694+
html-void-elements@^2.0.0:
8695+
version "2.0.1"
8696+
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
8697+
integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
8698+
86158699
html-webpack-plugin@^5.5.0:
86168700
version "5.5.0"
86178701
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50"
@@ -13111,6 +13195,15 @@ regjsparser@^0.8.2:
1311113195
dependencies:
1311213196
jsesc "~0.5.0"
1311313197

13198+
rehype-raw@^6.1.1:
13199+
version "6.1.1"
13200+
resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4"
13201+
integrity sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==
13202+
dependencies:
13203+
"@types/hast" "^2.0.0"
13204+
hast-util-raw "^7.2.0"
13205+
unified "^10.0.0"
13206+
1311413207
relateurl@^0.2.7:
1311513208
version "0.2.7"
1311613209
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
@@ -15292,6 +15385,14 @@ vfile-location@^3.0.0, vfile-location@^3.2.0:
1529215385
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c"
1529315386
integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==
1529415387

15388+
vfile-location@^4.0.0:
15389+
version "4.0.1"
15390+
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-4.0.1.tgz#06f2b9244a3565bef91f099359486a08b10d3a95"
15391+
integrity sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==
15392+
dependencies:
15393+
"@types/unist" "^2.0.0"
15394+
vfile "^5.0.0"
15395+
1529515396
vfile-message@^2.0.0:
1529615397
version "2.0.4"
1529715398
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
@@ -15410,6 +15511,11 @@ web-namespaces@^1.0.0:
1541015511
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec"
1541115512
integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==
1541215513

15514+
web-namespaces@^2.0.0:
15515+
version "2.0.1"
15516+
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
15517+
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
15518+
1541315519
webidl-conversions@^3.0.0:
1541415520
version "3.0.1"
1541515521
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
@@ -16112,3 +16218,8 @@ zwitch@^1.0.0:
1611216218
version "1.0.5"
1611316219
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
1611416220
integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==
16221+
16222+
zwitch@^2.0.0:
16223+
version "2.0.2"
16224+
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1"
16225+
integrity sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==

0 commit comments

Comments
 (0)