mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
fix(desktop): block markdown style injection (#904)
Forbid style tags and inline style attributes in rendered assistant markdown so model text blocks cannot inject global CSS into the desktop UI. Tested: cd desktop && bun run test -- src/components/markdown/MarkdownRenderer.test.tsx --run Tested: cd desktop && bun run lint Tested: cd desktop && bun run build Not-tested: bun run check:desktop still fails on unrelated existing MessageList timestamp and TabBar deleteSession test issues. Confidence: high Scope-risk: narrow
This commit is contained in:
parent
a169cba613
commit
1d20434746
@ -263,6 +263,45 @@ describe('MarkdownRenderer', () => {
|
||||
expect(link).toHaveAttribute('rel', expect.stringContaining('noopener'))
|
||||
})
|
||||
|
||||
it('strips style tags from assistant text before injecting markdown html', () => {
|
||||
const { container } = render(
|
||||
<MarkdownRenderer
|
||||
content={[
|
||||
'开始构建完整的 Web Linux 桌面环境。',
|
||||
'<function=Write>',
|
||||
'<parameter=content>',
|
||||
'<!DOCTYPE html>',
|
||||
'<html lang="zh-CN">',
|
||||
'<head>',
|
||||
'<style>',
|
||||
'* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }',
|
||||
'html, body { width: 100%; height: 100%; overflow: hidden; }',
|
||||
'</style>',
|
||||
'</head>',
|
||||
'<body>unsafe preview content</body>',
|
||||
'</html>',
|
||||
].join('\n')}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(container.querySelector('style')).not.toBeInTheDocument()
|
||||
expect(container).not.toHaveTextContent('overflow: hidden')
|
||||
expect(screen.getByText(/开始构建完整的 Web Linux 桌面环境/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('strips inline style attributes from assistant markdown html', () => {
|
||||
const { container } = render(
|
||||
<MarkdownRenderer
|
||||
content={'<div style="position: fixed; inset: 0; z-index: 999999">assistant text</div>'}
|
||||
/>,
|
||||
)
|
||||
|
||||
const injectedDiv = screen.getByText('assistant text')
|
||||
expect(injectedDiv).toBeInTheDocument()
|
||||
expect(injectedDiv).not.toHaveAttribute('style')
|
||||
expect(container.innerHTML).not.toContain('position: fixed')
|
||||
})
|
||||
|
||||
it('lets callers intercept markdown link clicks', () => {
|
||||
const onLinkClick = vi.fn().mockReturnValue(true)
|
||||
render(
|
||||
|
||||
@ -39,6 +39,12 @@ const MERMAID_DIAGRAM_START = /^(graph|flowchart|sequenceDiagram|classDiagram|st
|
||||
const CODE_FENCE_START = /^ {0,3}(`{3,}|~{3,})/
|
||||
const MATH_RENDER_CACHE_LIMIT = 200
|
||||
const mathRenderCache = new Map<string, string>()
|
||||
const MARKDOWN_SANITIZE_CONFIG = {
|
||||
ADD_TAGS: ['use'],
|
||||
ADD_ATTR: ['xlink:href'],
|
||||
FORBID_TAGS: ['style'],
|
||||
FORBID_ATTR: ['style'],
|
||||
}
|
||||
|
||||
function normalizeCodeLanguage(language: string | undefined): string | undefined {
|
||||
const normalized = language?.trim().split(/\s+/)[0]?.toLowerCase()
|
||||
@ -267,10 +273,7 @@ function renderMath(block: MathBlock): string {
|
||||
}
|
||||
|
||||
function enhanceMarkdownHtml(html: string, mathBlocks: MathBlock[]): string {
|
||||
const cleanHtml = DOMPurify.sanitize(html, {
|
||||
ADD_TAGS: ['use'],
|
||||
ADD_ATTR: ['xlink:href'],
|
||||
})
|
||||
const cleanHtml = DOMPurify.sanitize(html, MARKDOWN_SANITIZE_CONFIG)
|
||||
|
||||
const needsDomEnhancement = mathBlocks.length > 0 || /<(?:a|table)\b/i.test(cleanHtml)
|
||||
if (!needsDomEnhancement) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user