|
|
@@ -1,17 +1,27 @@
|
|
|
import MarkdownIt from 'markdown-it'
|
|
|
import DOMPurify from 'dompurify'
|
|
|
|
|
|
+// html: true lets LLM-emitted raw HTML (e.g. <span style="color:…">) reach DOMPurify.
|
|
|
+// DOMPurify + the allowlist below are the enforcement layer, not a trust assumption.
|
|
|
const md = new MarkdownIt({ html: true, breaks: false, linkify: false })
|
|
|
|
|
|
-// markdown-it produces table/heading/list HTML; the only raw HTML the LLM
|
|
|
-// emits is <span style="color:red">…</span> for highlights. Allow exactly that.
|
|
|
+// style is needed only for <span> colour highlights and markdown-it's
|
|
|
+// table-column alignment on <td>/<th>; strip it everywhere else so an
|
|
|
+// unexpected LLM style cannot disrupt page layout.
|
|
|
+const STYLE_TAGS = new Set(['span', 'td', 'th'])
|
|
|
+DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
|
|
+ if (node.hasAttribute('style') && !STYLE_TAGS.has(node.tagName.toLowerCase())) {
|
|
|
+ node.removeAttribute('style')
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
const ALLOWED_TAGS = [
|
|
|
'h1', 'h2', 'h3', 'h4', 'h5', 'p', 'br', 'hr',
|
|
|
'ul', 'ol', 'li', 'strong', 'em', 'del', 'code', 'pre',
|
|
|
'blockquote', 'span',
|
|
|
'table', 'thead', 'tbody', 'tr', 'th', 'td',
|
|
|
]
|
|
|
-const ALLOWED_ATTR = ['style', 'align']
|
|
|
+const ALLOWED_ATTR = ['style']
|
|
|
|
|
|
/** Render class-report Markdown to sanitised HTML safe for v-html. */
|
|
|
export function renderReportMarkdown(src: string): string {
|