Skip to content

Commit 061a765

Browse files
authored
fix: sanitizer svg to avoid xss (#16608)
1 parent acd7fea commit 061a765

File tree

3 files changed

+12
-17
lines changed

3 files changed

+12
-17
lines changed

web/app/components/base/markdown.tsx

+9-16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import SyntaxHighlighter from 'react-syntax-highlighter'
1010
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
1111
import { Component, memo, useMemo, useRef, useState } from 'react'
1212
import type { CodeComponent } from 'react-markdown/lib/ast-to-react'
13+
import SVGRenderer from './svg-gallery'
1314
import cn from '@/utils/classnames'
1415
import CopyBtn from '@/app/components/base/copy-btn'
1516
import SVGBtn from '@/app/components/base/svg'
@@ -118,13 +119,13 @@ const CodeBlock: CodeComponent = memo(({ inline, className, children, ...props }
118119
</div>
119120
)
120121
}
121-
// else if (language === 'svg' && isSVG) {
122-
// return (
123-
// <ErrorBoundary>
124-
// <SVGRenderer content={content} />
125-
// </ErrorBoundary>
126-
// )
127-
// }
122+
else if (language === 'svg' && isSVG) {
123+
return (
124+
<ErrorBoundary>
125+
<SVGRenderer content={content} />
126+
</ErrorBoundary>
127+
)
128+
}
128129
else {
129130
return (
130131
<SyntaxHighlighter
@@ -224,16 +225,8 @@ const Link = ({ node, ...props }: any) => {
224225
}
225226
}
226227

227-
function escapeSVGTags(htmlString: string): string {
228-
return htmlString.replace(/(<svg[\s\S]*?>)([\s\S]*?)(<\/svg>)/gi, (match: string, openTag: string, innerContent: string, closeTag: string): string => {
229-
return openTag.replace(/</g, '&lt;').replace(/>/g, '&gt;')
230-
+ innerContent.replace(/</g, '&lt;').replace(/>/g, '&gt;')
231-
+ closeTag.replace(/</g, '&lt;').replace(/>/g, '&gt;')
232-
})
233-
}
234-
235228
export function Markdown(props: { content: string; className?: string }) {
236-
const latexContent = preprocessLaTeX(escapeSVGTags(props.content))
229+
const latexContent = preprocessLaTeX(props.content)
237230
return (
238231
<div className={cn(props.className, 'markdown-body')}>
239232
<ReactMarkdown

web/app/components/base/svg-gallery/index.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useEffect, useRef, useState } from 'react'
22
import { SVG } from '@svgdotjs/svg.js'
3+
import DOMPurify from 'dompurify'
34
import ImagePreview from '@/app/components/base/image-uploader/image-preview'
45

56
export const SVGRenderer = ({ content }: { content: string }) => {
@@ -44,7 +45,7 @@ export const SVGRenderer = ({ content }: { content: string }) => {
4445

4546
svgRef.current.style.width = `${Math.min(originalWidth, 298)}px`
4647

47-
const rootElement = draw.svg(content)
48+
const rootElement = draw.svg(DOMPurify.sanitize(content))
4849

4950
rootElement.click(() => {
5051
setImagePreview(svgToDataURL(svgElement as Element))

web/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"crypto-js": "^4.2.0",
5252
"dayjs": "^1.11.7",
5353
"decimal.js": "^10.4.3",
54+
"dompurify": "^3.2.4",
5455
"echarts": "^5.5.1",
5556
"echarts-for-react": "^3.0.2",
5657
"elkjs": "^0.9.3",

0 commit comments

Comments
 (0)