mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-26 15:03:34 +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'))
|
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', () => {
|
it('lets callers intercept markdown link clicks', () => {
|
||||||
const onLinkClick = vi.fn().mockReturnValue(true)
|
const onLinkClick = vi.fn().mockReturnValue(true)
|
||||||
render(
|
render(
|
||||||
|
|||||||
@ -39,6 +39,12 @@ const MERMAID_DIAGRAM_START = /^(graph|flowchart|sequenceDiagram|classDiagram|st
|
|||||||
const CODE_FENCE_START = /^ {0,3}(`{3,}|~{3,})/
|
const CODE_FENCE_START = /^ {0,3}(`{3,}|~{3,})/
|
||||||
const MATH_RENDER_CACHE_LIMIT = 200
|
const MATH_RENDER_CACHE_LIMIT = 200
|
||||||
const mathRenderCache = new Map<string, string>()
|
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 {
|
function normalizeCodeLanguage(language: string | undefined): string | undefined {
|
||||||
const normalized = language?.trim().split(/\s+/)[0]?.toLowerCase()
|
const normalized = language?.trim().split(/\s+/)[0]?.toLowerCase()
|
||||||
@ -267,10 +273,7 @@ function renderMath(block: MathBlock): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function enhanceMarkdownHtml(html: string, mathBlocks: MathBlock[]): string {
|
function enhanceMarkdownHtml(html: string, mathBlocks: MathBlock[]): string {
|
||||||
const cleanHtml = DOMPurify.sanitize(html, {
|
const cleanHtml = DOMPurify.sanitize(html, MARKDOWN_SANITIZE_CONFIG)
|
||||||
ADD_TAGS: ['use'],
|
|
||||||
ADD_ATTR: ['xlink:href'],
|
|
||||||
})
|
|
||||||
|
|
||||||
const needsDomEnhancement = mathBlocks.length > 0 || /<(?:a|table)\b/i.test(cleanHtml)
|
const needsDomEnhancement = mathBlocks.length > 0 || /<(?:a|table)\b/i.test(cleanHtml)
|
||||||
if (!needsDomEnhancement) {
|
if (!needsDomEnhancement) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user