From d723b7621489ad61e559141a9c15221e24685686 Mon Sep 17 00:00:00 2001 From: Juan-LukeKlopper Date: Thu, 6 Jun 2024 17:43:35 +0200 Subject: [PATCH] fix: sanitize and style html in markdown --- package-lock.json | 7 +++++ package.json | 1 + src/components/ProposalDetails.js | 45 +++++++++++++------------------ 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1864df9e..5673bcb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "buffer": "^6.0.3", "compare-versions": "^5.0.1", "cosmjs-types": "^0.4.1", + "dompurify": "^3.1.5", "dotenv": "^16.4.5", "fuzzy-search": "^3.2.1", "html-react-parser": "^5.1.10", @@ -5268,6 +5269,12 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz", + "integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==", + "license": "(MPL-2.0 OR Apache-2.0)" + }, "node_modules/domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", diff --git a/package.json b/package.json index edad6854..1d2fe86b 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "buffer": "^6.0.3", "compare-versions": "^5.0.1", "cosmjs-types": "^0.4.1", + "dompurify": "^3.1.5", "dotenv": "^16.4.5", "fuzzy-search": "^3.2.1", "html-react-parser": "^5.1.10", diff --git a/src/components/ProposalDetails.js b/src/components/ProposalDetails.js index e1020fe9..937ea941 100644 --- a/src/components/ProposalDetails.js +++ b/src/components/ProposalDetails.js @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import Moment from 'react-moment'; import {micromark} from 'micromark'; import {gfm, gfmHtml} from 'micromark-extension-gfm'; -import parse,{ domToReact } from 'html-react-parser'; +import DOMPurify from 'dompurify'; import { Table, @@ -27,36 +27,27 @@ function ProposalDetails(props) { const fixDescription = description?.replace(/\\n/g, ' \n') - const transformElement = (node) => { - if (!node || !node.name) { - return node; - } + const transformHTMLString = (htmlString, isSpam) => { + let transformedString = htmlString; - if (proposal.isSpam && node.name === 'a') { - return {node.children[0].data}; - } + // Transform headings + transformedString = transformedString.replace(/

(.*?)<\/h1>/g, '

$1
'); + transformedString = transformedString.replace(/(.*?)<\/h[2-6]>/g, '
$1
'); - switch (node.name) { - case 'h1': - return
{domToReact(node.children, { replace: transformElement })}
; - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - return
{domToReact(node.children, { replace: transformElement })}
; - case 'table': - return {domToReact(node.children, { replace: transformElement })}
; - default: - return node; + // Remove all tags if proposal is spam + if (isSpam) { + transformedString = transformedString.replace(/]*>(.*?)<\/a>/g, '$1'); } + + // Apply table class + transformedString = transformedString.replace(//g, '
'); + + return transformedString; }; - const basicHTMLfromMarkdown = micromark(fixDescription) - const fancyHTMLfromMarkdown = micromark(fixDescription, { extensions: [gfm()], htmlExtensions: [gfmHtml()] }) - - console.log("basicHTMLfromMarkdown", basicHTMLfromMarkdown); - console.log("fancyHTMLfromMarkdown", fancyHTMLfromMarkdown); + const htmlDescription = micromark(fixDescription, { extensions: [gfm()], htmlExtensions: [gfmHtml()] }) + const sanitizedHtml = DOMPurify.sanitize(htmlDescription); + const transformedDescription = transformHTMLString(htmlDescription, proposal.isSpam); useEffect(() => { if(props.address !== props.wallet?.address && props.granters.includes(props.address)){ @@ -206,7 +197,7 @@ function ProposalDetails(props) {
{title}
-
+