diff --git a/GUI/package-lock.json b/GUI/package-lock.json index dacaca01..6f0ddf2f 100644 --- a/GUI/package-lock.json +++ b/GUI/package-lock.json @@ -60,6 +60,7 @@ "react-router-dom": "^6.6.2", "react-textarea-autosize": "^8.4.0", "rxjs": "^7.8.0", + "sanitize-html": "^2.17.0", "sass": "^1.57.1", "sass-loader": "^13.2.0", "to-json-schema": "^0.2.5", @@ -81,6 +82,7 @@ "@types/react": "^18.2.0", "@types/react-datepicker": "^4.8.0", "@types/react-dom": "^18.2.0", + "@types/sanitize-html": "^2.16.0", "@types/to-json-schema": "^0.2.1", "@types/uuid": "^9.0.1", "@vitejs/plugin-react": "^5.1.1", @@ -5748,6 +5750,15 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/sanitize-html": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.0.tgz", + "integrity": "sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==", + "dev": true, + "dependencies": { + "htmlparser2": "^8.0.0" + } + }, "node_modules/@types/to-json-schema": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@types/to-json-schema/-/to-json-schema-0.2.4.tgz", @@ -7424,6 +7435,14 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -7905,7 +7924,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9056,6 +9074,24 @@ "void-elements": "3.1.0" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -9508,6 +9544,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -10339,7 +10383,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -10704,6 +10747,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -10818,7 +10866,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -10854,7 +10901,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -11805,6 +11851,19 @@ "dev": true, "license": "MIT" }, + "node_modules/sanitize-html": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz", + "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, "node_modules/sass": { "version": "1.97.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz", diff --git a/GUI/package.json b/GUI/package.json index cc56b0a5..fb414b99 100644 --- a/GUI/package.json +++ b/GUI/package.json @@ -56,6 +56,7 @@ "react-router-dom": "^6.6.2", "react-textarea-autosize": "^8.4.0", "rxjs": "^7.8.0", + "sanitize-html": "^2.17.0", "sass": "^1.57.1", "sass-loader": "^13.2.0", "to-json-schema": "^0.2.5", @@ -101,6 +102,7 @@ "@types/react": "^18.2.0", "@types/react-datepicker": "^4.8.0", "@types/react-dom": "^18.2.0", + "@types/sanitize-html": "^2.16.0", "@types/to-json-schema": "^0.2.1", "@types/uuid": "^9.0.1", "@vitejs/plugin-react": "^5.1.1", diff --git a/GUI/src/components/Markdowify/index.tsx b/GUI/src/components/Markdowify/index.tsx index 578c94b6..c98f1240 100644 --- a/GUI/src/components/Markdowify/index.tsx +++ b/GUI/src/components/Markdowify/index.tsx @@ -1,5 +1,6 @@ import Markdown from 'markdown-to-jsx'; import React, { useState } from 'react'; +import sanitizeHtml from 'sanitize-html'; interface MarkdownifyProps { message: string | undefined; @@ -43,9 +44,11 @@ const LinkPreview: React.FC<{ const hasSpecialFormat = (m: string) => m.includes('\n\n') && m.indexOf('.') > 0 && m.indexOf(':') > m.indexOf('.'); function formatMessage(message?: string): string { - if (!message) return ''; + const sanitizedMessage = sanitizeHtml(message ?? ''); - const filteredMessage = message + if (!sanitizedMessage) return ''; + + const filteredMessage = sanitizedMessage .replaceAll(/\\?\$b\w*/g, '') .replaceAll(/\\?\$v\w*/g, '') .replaceAll(/\\?\$g\w*/g, '');