diff --git a/components/email/ComposeEmail.tsx b/components/email/ComposeEmail.tsx index e65cc5e5..230cd6f5 100644 --- a/components/email/ComposeEmail.tsx +++ b/components/email/ComposeEmail.tsx @@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card'; import { decodeEmail } from '@/lib/mail-parser-wrapper'; +import DOMPurify from 'isomorphic-dompurify'; interface ComposeEmailProps { initialEmail?: EmailMessage | null; @@ -94,9 +95,9 @@ export default function ComposeEmail({ // New function to initialize forwarded email using same approach as Panel 3 const initializeForwardedEmail = async () => { - if (!initialEmail || !initialEmail.content) { - console.error('No email content available for forwarding'); - setBody('
---------- Forwarded message ---------
+From: ${initialEmail.from || ''}
+Date: ${formatDate(initialEmail.date)}
+Subject: ${initialEmail.subject || ''}
+To: ${initialEmail.to || ''}
+---------- Forwarded message ---------
+From: ${initialEmail.from || ''}
+Date: ${formatDate(initialEmail.date)}
+Subject: ${initialEmail.subject || ''}
+To: ${initialEmail.to || ''}
+No content available
; - // Sanitize HTML content - const sanitizedContent = DOMPurify.sanitize(email.content, { - ADD_TAGS: ['style', 'table', 'thead', 'tbody', 'tr', 'td', 'th'], - ADD_ATTR: ['colspan', 'rowspan', 'style', 'width', 'height'] - }); - - return ( - - ); + try { + // Use DOMPurify directly with enhanced sanitization options + const sanitizedContent = DOMPurify.sanitize(email.content, { + ADD_TAGS: ['style', 'meta', 'link', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'hr', 'font', 'div', 'span', 'a', 'img', 'b', 'strong', 'i', 'em', 'u', 'br', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'code', 'center', 'section', 'header', 'footer', 'article', 'nav', 'keyframes'], + ADD_ATTR: ['*', 'colspan', 'rowspan', 'cellpadding', 'cellspacing', 'border', 'bgcolor', 'width', 'height', 'align', 'valign', 'class', 'id', 'style', 'color', 'face', 'size', 'background', 'src', 'href', 'target', 'rel', 'alt', 'title', 'name', 'animation', 'animation-name', 'animation-duration', 'animation-fill-mode'], + ALLOW_UNKNOWN_PROTOCOLS: true, + WHOLE_DOCUMENT: true, + KEEP_CONTENT: true, + RETURN_DOM: false, + FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'select', 'option', 'textarea', 'canvas', 'video', 'audio'], + FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout', 'onchange', 'onsubmit'], + USE_PROFILES: { html: true, svg: false, svgFilters: false, mathMl: false }, + FORCE_BODY: true + }); + + return ( + + ); + } catch (error) { + console.error('Error rendering email content:', error); + returnError displaying email content
; + } }; // Format the date diff --git a/lib/mail-parser-wrapper.ts b/lib/mail-parser-wrapper.ts index 1216719b..6f23bd95 100644 --- a/lib/mail-parser-wrapper.ts +++ b/lib/mail-parser-wrapper.ts @@ -105,14 +105,16 @@ export function cleanHtml(html: string): string { try { // Enhanced configuration to preserve more HTML elements for complex emails return DOMPurify.sanitize(html, { - ADD_TAGS: ['style', 'meta', 'link', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'hr', 'font', 'div', 'span', 'a', 'img', 'b', 'strong', 'i', 'em', 'u', 'br', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'code', 'center', 'section', 'header', 'footer', 'article', 'nav'], - ADD_ATTR: ['*', 'colspan', 'rowspan', 'cellpadding', 'cellspacing', 'border', 'bgcolor', 'width', 'height', 'align', 'valign', 'class', 'id', 'style', 'color', 'face', 'size', 'background', 'src', 'href', 'target', 'rel', 'alt', 'title', 'name'], + ADD_TAGS: ['style', 'meta', 'link', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'hr', 'font', 'div', 'span', 'a', 'img', 'b', 'strong', 'i', 'em', 'u', 'br', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'code', 'center', 'section', 'header', 'footer', 'article', 'nav', 'keyframes'], + ADD_ATTR: ['*', 'colspan', 'rowspan', 'cellpadding', 'cellspacing', 'border', 'bgcolor', 'width', 'height', 'align', 'valign', 'class', 'id', 'style', 'color', 'face', 'size', 'background', 'src', 'href', 'target', 'rel', 'alt', 'title', 'name', 'animation', 'animation-name', 'animation-duration', 'animation-fill-mode'], ALLOW_UNKNOWN_PROTOCOLS: true, WHOLE_DOCUMENT: true, KEEP_CONTENT: true, RETURN_DOM: false, FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'select', 'option', 'textarea', 'canvas', 'video', 'audio'], - FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout', 'onchange', 'onsubmit'] + FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout', 'onchange', 'onsubmit'], + USE_PROFILES: { html: true, svg: false, svgFilters: false, mathMl: false }, + FORCE_BODY: true }); } catch (error) { console.error('Error cleaning HTML:', error); diff --git a/lib/server/email-parser.ts b/lib/server/email-parser.ts index 587644da..740633ef 100644 --- a/lib/server/email-parser.ts +++ b/lib/server/email-parser.ts @@ -1,20 +1,16 @@ import { simpleParser } from 'mailparser'; -function cleanHtml(html: string): string { +export function cleanHtml(html: string): string { try { - // Basic HTML cleaning without DOMPurify + // More permissive cleaning that preserves styling but removes potentially harmful elements return html - .replace(/