diff --git a/backend/src/main/resources/html-sanitization-config.json b/backend/src/main/resources/html-sanitization-config.json index b6779d6..f1bd063 100644 --- a/backend/src/main/resources/html-sanitization-config.json +++ b/backend/src/main/resources/html-sanitization-config.json @@ -5,7 +5,8 @@ "sup", "sub", "small", "big", "mark", "pre", "code", "kbd", "samp", "var", "ul", "ol", "li", "dl", "dt", "dd", "a", "table", "thead", "tbody", "tfoot", "tr", "th", "td", "caption", "colgroup", "col", - "blockquote", "cite", "q", "hr", "details", "summary" + "blockquote", "cite", "q", "hr", "details", "summary", + "section", "article", "font", "center", "abbr", "dfn", "tt" ], "allowedAttributes": { "p": ["class", "style"], @@ -32,12 +33,44 @@ "pre": ["class", "style"], "code": ["class", "style"], "details": ["class", "style"], - "summary": ["class", "style"] + "summary": ["class", "style"], + "section": ["class", "style"], + "article": ["class", "style"], + "font": ["class", "style", "color", "size", "face"], + "center": ["class", "style"], + "abbr": ["class", "style", "title"], + "dfn": ["class", "style"], + "tt": ["class", "style"], + "b": ["class", "style"], + "strong": ["class", "style"], + "i": ["class", "style"], + "em": ["class", "style"], + "u": ["class", "style"], + "s": ["class", "style"], + "small": ["class", "style"], + "big": ["class", "style"], + "mark": ["class", "style"], + "sup": ["class", "style"], + "sub": ["class", "style"], + "del": ["class", "style"], + "ins": ["class", "style"], + "strike": ["class", "style"], + "kbd": ["class", "style"], + "samp": ["class", "style"], + "var": ["class", "style"] }, "allowedCssProperties": [ "color", "background-color", "font-size", "font-weight", "font-style", "text-align", "text-decoration", "margin", - "padding", "text-indent", "line-height" + "padding", "text-indent", "line-height", + "border", "border-color", "border-width", "border-style", + "font-family", "font-variant", "font-variant-ligatures", + "font-variant-caps", "font-variant-numeric", "font-variant-east-asian", + "font-variant-alternates", "font-variant-position", "font-variant-emoji", + "font-stretch", "letter-spacing", "word-spacing", + "text-transform", "text-shadow", "white-space", + "vertical-align", "display", "float", "clear", + "width", "height", "min-width", "min-height", "max-width", "max-height" ], "removedAttributes": { "a": ["href", "target"] diff --git a/frontend/src/components/stories/RichTextEditor.tsx b/frontend/src/components/stories/RichTextEditor.tsx index 62fda84..7935f35 100644 --- a/frontend/src/components/stories/RichTextEditor.tsx +++ b/frontend/src/components/stories/RichTextEditor.tsx @@ -3,7 +3,7 @@ import { useState, useRef, useEffect } from 'react'; import { Textarea } from '../ui/Input'; import Button from '../ui/Button'; -import { sanitizeHtmlSync, preloadSanitizationConfig } from '../../lib/sanitization'; +import { sanitizeHtmlSync } from '../../lib/sanitization'; interface RichTextEditorProps { value: string; @@ -25,7 +25,11 @@ export default function RichTextEditor({ // Preload sanitization config useEffect(() => { - preloadSanitizationConfig().catch(console.error); + // Clear cache and reload config to get latest sanitization rules + import('../../lib/sanitization').then(({ clearSanitizationCache, preloadSanitizationConfig }) => { + clearSanitizationCache(); + preloadSanitizationConfig().catch(console.error); + }); }, []); const handleVisualChange = (e: React.ChangeEvent) => { @@ -109,7 +113,15 @@ export default function RichTextEditor({ console.log('Raw HTML:', htmlContent.substring(0, 500)); const sanitizedHtml = sanitizeHtmlSync(htmlContent); - console.log('Sanitized HTML:', sanitizedHtml.substring(0, 500)); + console.log('Sanitized HTML length:', sanitizedHtml.length); + console.log('Sanitized HTML preview:', sanitizedHtml.substring(0, 500)); + + // Check if sanitization removed too much content + const ratio = sanitizedHtml.length / htmlContent.length; + console.log('Sanitization ratio (kept/original):', ratio.toFixed(3)); + if (ratio < 0.1) { + console.warn('Sanitization removed >90% of content - this might be too aggressive'); + } // Insert at cursor position instead of just appending const textarea = visualTextareaRef.current;