mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-12 06:39:06 +08:00
fix: sanitizer svg to avoid xss (#16606)
This commit is contained in:
parent
9701b573e0
commit
16b6ffd915
@ -27,6 +27,7 @@ import ThinkBlock from '@/app/components/base/markdown-blocks/think-block'
|
|||||||
import { Theme } from '@/types/app'
|
import { Theme } from '@/types/app'
|
||||||
import useTheme from '@/hooks/use-theme'
|
import useTheme from '@/hooks/use-theme'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import SVGRenderer from './svg-gallery'
|
||||||
|
|
||||||
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
||||||
const capitalizationLanguageNameMap: Record<string, string> = {
|
const capitalizationLanguageNameMap: Record<string, string> = {
|
||||||
@ -136,14 +137,13 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }: any) =>
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Attention: SVGRenderer has xss vulnerability
|
else if (language === 'svg' && isSVG) {
|
||||||
// else if (language === 'svg' && isSVG) {
|
return (
|
||||||
// return (
|
<ErrorBoundary>
|
||||||
// <ErrorBoundary>
|
<SVGRenderer content={content} />
|
||||||
// <SVGRenderer content={content} />
|
</ErrorBoundary>
|
||||||
// </ErrorBoundary>
|
)
|
||||||
// )
|
}
|
||||||
// }
|
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
@ -240,19 +240,11 @@ const Link = ({ node, ...props }: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeSVGTags(htmlString: string): string {
|
|
||||||
return htmlString.replace(/(<svg[\s\S]*?>)([\s\S]*?)(<\/svg>)/gi, (match: string, openTag: string, innerContent: string, closeTag: string): string => {
|
|
||||||
return openTag.replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
+ innerContent.replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
+ closeTag.replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) {
|
export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) {
|
||||||
const latexContent = flow([
|
const latexContent = flow([
|
||||||
preprocessThinkTag,
|
preprocessThinkTag,
|
||||||
preprocessLaTeX,
|
preprocessLaTeX,
|
||||||
])(escapeSVGTags(props.content))
|
])(props.content)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('markdown-body', '!text-text-primary', props.className)}>
|
<div className={cn('markdown-body', '!text-text-primary', props.className)}>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { SVG } from '@svgdotjs/svg.js'
|
import { SVG } from '@svgdotjs/svg.js'
|
||||||
import ImagePreview from '@/app/components/base/image-uploader/image-preview'
|
import ImagePreview from '@/app/components/base/image-uploader/image-preview'
|
||||||
|
import DOMPurify from 'dompurify'
|
||||||
|
|
||||||
export const SVGRenderer = ({ content }: { content: string }) => {
|
export const SVGRenderer = ({ content }: { content: string }) => {
|
||||||
const svgRef = useRef<HTMLDivElement>(null)
|
const svgRef = useRef<HTMLDivElement>(null)
|
||||||
@ -44,7 +45,7 @@ export const SVGRenderer = ({ content }: { content: string }) => {
|
|||||||
|
|
||||||
svgRef.current.style.width = `${Math.min(originalWidth, 298)}px`
|
svgRef.current.style.width = `${Math.min(originalWidth, 298)}px`
|
||||||
|
|
||||||
const rootElement = draw.svg(content)
|
const rootElement = draw.svg(DOMPurify.sanitize(content))
|
||||||
|
|
||||||
rootElement.click(() => {
|
rootElement.click(() => {
|
||||||
setImagePreview(svgToDataURL(svgElement as Element))
|
setImagePreview(svgToDataURL(svgElement as Element))
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"decimal.js": "^10.4.3",
|
"decimal.js": "^10.4.3",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
"echarts": "^5.5.1",
|
"echarts": "^5.5.1",
|
||||||
"echarts-for-react": "^3.0.2",
|
"echarts-for-react": "^3.0.2",
|
||||||
"elkjs": "^0.9.3",
|
"elkjs": "^0.9.3",
|
||||||
@ -132,10 +133,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^4.1.1",
|
"@antfu/eslint-config": "^4.1.1",
|
||||||
"@eslint/js": "^9.20.0",
|
|
||||||
"@chromatic-com/storybook": "^3.1.0",
|
"@chromatic-com/storybook": "^3.1.0",
|
||||||
"@eslint-react/eslint-plugin": "^1.15.0",
|
"@eslint-react/eslint-plugin": "^1.15.0",
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
|
"@eslint/js": "^9.20.0",
|
||||||
"@faker-js/faker": "^9.0.3",
|
"@faker-js/faker": "^9.0.3",
|
||||||
"@next/eslint-plugin-next": "^15.2.3",
|
"@next/eslint-plugin-next": "^15.2.3",
|
||||||
"@rgrove/parse-xml": "^4.1.0",
|
"@rgrove/parse-xml": "^4.1.0",
|
||||||
@ -174,11 +175,11 @@
|
|||||||
"code-inspector-plugin": "^0.18.1",
|
"code-inspector-plugin": "^0.18.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^9.20.1",
|
"eslint": "^9.20.1",
|
||||||
|
"eslint-config-next": "^15.0.0",
|
||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"eslint-plugin-storybook": "^0.11.2",
|
"eslint-plugin-storybook": "^0.11.2",
|
||||||
"eslint-plugin-tailwindcss": "^3.18.0",
|
"eslint-plugin-tailwindcss": "^3.18.0",
|
||||||
"eslint-config-next": "^15.0.0",
|
|
||||||
"husky": "^9.1.6",
|
"husky": "^9.1.6",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
|
11
web/pnpm-lock.yaml
generated
11
web/pnpm-lock.yaml
generated
@ -121,6 +121,9 @@ importers:
|
|||||||
decimal.js:
|
decimal.js:
|
||||||
specifier: ^10.4.3
|
specifier: ^10.4.3
|
||||||
version: 10.4.3
|
version: 10.4.3
|
||||||
|
dompurify:
|
||||||
|
specifier: ^3.2.4
|
||||||
|
version: 3.2.4
|
||||||
echarts:
|
echarts:
|
||||||
specifier: ^5.5.1
|
specifier: ^5.5.1
|
||||||
version: 5.5.1
|
version: 5.5.1
|
||||||
@ -4299,8 +4302,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
dompurify@3.2.3:
|
dompurify@3.2.4:
|
||||||
resolution: {integrity: sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==}
|
resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==}
|
||||||
|
|
||||||
domutils@2.8.0:
|
domutils@2.8.0:
|
||||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||||
@ -13070,7 +13073,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
dompurify@3.2.3:
|
dompurify@3.2.4:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/trusted-types': 2.0.7
|
'@types/trusted-types': 2.0.7
|
||||||
|
|
||||||
@ -15688,7 +15691,7 @@ snapshots:
|
|||||||
d3-sankey: 0.12.3
|
d3-sankey: 0.12.3
|
||||||
dagre-d3-es: 7.0.11
|
dagre-d3-es: 7.0.11
|
||||||
dayjs: 1.11.13
|
dayjs: 1.11.13
|
||||||
dompurify: 3.2.3
|
dompurify: 3.2.4
|
||||||
katex: 0.16.21
|
katex: 0.16.21
|
||||||
khroma: 2.1.0
|
khroma: 2.1.0
|
||||||
lodash-es: 4.17.21
|
lodash-es: 4.17.21
|
||||||
|
Loading…
x
Reference in New Issue
Block a user