|
@@ -21,7 +21,6 @@ import ImageGallery from '@/app/components/base/image-gallery'
|
|
|
import { useChatContext } from '@/app/components/base/chat/chat/context'
|
|
|
import VideoGallery from '@/app/components/base/video-gallery'
|
|
|
import AudioGallery from '@/app/components/base/audio-gallery'
|
|
|
-import SVGRenderer from '@/app/components/base/svg-gallery'
|
|
|
import MarkdownButton from '@/app/components/base/markdown-blocks/button'
|
|
|
import MarkdownForm from '@/app/components/base/markdown-blocks/form'
|
|
|
import ThinkBlock from '@/app/components/base/markdown-blocks/think-block'
|
|
@@ -137,13 +136,14 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }: any) =>
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
- else if (language === 'svg' && isSVG) {
|
|
|
- return (
|
|
|
- <ErrorBoundary>
|
|
|
- <SVGRenderer content={content} />
|
|
|
- </ErrorBoundary>
|
|
|
- )
|
|
|
- }
|
|
|
+ // Attention: SVGRenderer has xss vulnerability
|
|
|
+ // else if (language === 'svg' && isSVG) {
|
|
|
+ // return (
|
|
|
+ // <ErrorBoundary>
|
|
|
+ // <SVGRenderer content={content} />
|
|
|
+ // </ErrorBoundary>
|
|
|
+ // )
|
|
|
+ // }
|
|
|
else {
|
|
|
return (
|
|
|
<SyntaxHighlighter
|
|
@@ -175,7 +175,7 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }: any) =>
|
|
|
<div className='flex items-center gap-1'>
|
|
|
{(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
|
|
|
<ActionButton>
|
|
|
- <CopyIcon content={String(children).replace(/\n$/, '')}/>
|
|
|
+ <CopyIcon content={String(children).replace(/\n$/, '')} />
|
|
|
</ActionButton>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -240,11 +240,20 @@ 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[] }) {
|
|
|
const latexContent = flow([
|
|
|
preprocessThinkTag,
|
|
|
preprocessLaTeX,
|
|
|
- ])(props.content)
|
|
|
+ ])(escapeSVGTags(props.content))
|
|
|
+
|
|
|
return (
|
|
|
<div className={cn('markdown-body', '!text-text-primary', props.className)}>
|
|
|
<ReactMarkdown
|