From 636343019c5fd54eb8db23f1ac8607c772f2fce3 Mon Sep 17 00:00:00 2001 From: alma Date: Thu, 1 May 2025 09:59:00 +0200 Subject: [PATCH] courrier preview --- app/api/parse-email/route.ts | 2 +- components/email/ComposeEmail.tsx | 2 +- components/email/EmailContent.tsx | 2 +- components/email/EmailContentDisplay.tsx | 13 +--- components/email/RichEmailEditor.tsx | 2 +- components/ui/rich-text-editor.tsx | 4 +- hooks/use-email-fetch.ts | 2 +- lib/server/email-parser.ts | 2 +- lib/utils/dom-sanitizer.ts | 83 ------------------------ lib/utils/email-adapters.ts | 2 +- lib/utils/email-content.ts | 78 ++++++++++++++++++---- lib/utils/email-formatter.ts | 33 ++++++++-- lib/utils/email-mime-decoder.ts | 10 +-- lib/utils/email-utils.ts | 67 +++++++++++++++++-- 14 files changed, 174 insertions(+), 128 deletions(-) delete mode 100644 lib/utils/dom-sanitizer.ts diff --git a/app/api/parse-email/route.ts b/app/api/parse-email/route.ts index c2f3a015..7af4e6a1 100644 --- a/app/api/parse-email/route.ts +++ b/app/api/parse-email/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; import { parseEmail } from '@/lib/server/email-parser'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import { sanitizeHtml } from '@/lib/utils/email-formatter'; interface EmailAddress { name?: string; diff --git a/components/email/ComposeEmail.tsx b/components/email/ComposeEmail.tsx index d4cabaf1..41aaf28e 100644 --- a/components/email/ComposeEmail.tsx +++ b/components/email/ComposeEmail.tsx @@ -6,7 +6,7 @@ import { } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import DOMPurify from 'isomorphic-dompurify'; import { DropdownMenu, DropdownMenuContent, diff --git a/components/email/EmailContent.tsx b/components/email/EmailContent.tsx index 46d3e9b3..f6341bbf 100644 --- a/components/email/EmailContent.tsx +++ b/components/email/EmailContent.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Loader2, Paperclip, Download } from 'lucide-react'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import { sanitizeHtml } from '@/lib/utils/email-formatter'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; diff --git a/components/email/EmailContentDisplay.tsx b/components/email/EmailContentDisplay.tsx index 61c0b0ab..3c23aa89 100644 --- a/components/email/EmailContentDisplay.tsx +++ b/components/email/EmailContentDisplay.tsx @@ -3,7 +3,7 @@ import React, { useMemo } from 'react'; import { EmailContent } from '@/types/email'; import { detectTextDirection, applyTextDirection } from '@/lib/utils/text-direction'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import DOMPurify from 'isomorphic-dompurify'; interface EmailContentDisplayProps { content: EmailContent | null | undefined; @@ -96,7 +96,7 @@ const EmailContentDisplay: React.FC = ({ // Sanitize HTML content and apply proper direction const sanitizedHTML = useMemo(() => { - const clean = sanitizeHtml(processedHTML); + const clean = DOMPurify.sanitize(processedHTML); // Apply text direction consistently using our utility return applyTextDirection(clean, safeContent.text); @@ -124,18 +124,11 @@ const EmailContentDisplay: React.FC = ({ width: 100%; } - /* Enhanced RTL styling - handle direction at every level */ - [dir="rtl"] { - text-align: right; - } - - /* Ensure images don't overflow their containers */ .email-content-inner img { max-width: 100%; height: auto; } - /* Blockquote styling for LTR content */ .email-content-inner blockquote { margin: 10px 0; padding-left: 15px; @@ -145,7 +138,7 @@ const EmailContentDisplay: React.FC = ({ border-radius: 4px; } - /* Special styling for RTL blockquotes - handled via attribute selector */ + /* RTL blockquote styling will be handled by the direction attribute now */ [dir="rtl"] blockquote { padding-left: 0; padding-right: 15px; diff --git a/components/email/RichEmailEditor.tsx b/components/email/RichEmailEditor.tsx index 3880e5ce..6cfb0693 100644 --- a/components/email/RichEmailEditor.tsx +++ b/components/email/RichEmailEditor.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react'; import 'quill/dist/quill.snow.css'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import { sanitizeHtml } from '@/lib/utils/email-utils'; interface RichEmailEditorProps { initialContent: string; diff --git a/components/ui/rich-text-editor.tsx b/components/ui/rich-text-editor.tsx index 5e6e7aa7..6b2c755a 100644 --- a/components/ui/rich-text-editor.tsx +++ b/components/ui/rich-text-editor.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react'; import { detectTextDirection } from '@/lib/utils/text-direction'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import DOMPurify from 'isomorphic-dompurify'; interface RichTextEditorProps { /** Initial HTML content */ @@ -52,7 +52,7 @@ const RichTextEditor = forwardRef(({ useEffect(() => { if (internalEditorRef.current) { // Clean the initial content - const cleanContent = sanitizeHtml(initialContent); + const cleanContent = DOMPurify.sanitize(initialContent); internalEditorRef.current.innerHTML = cleanContent; // Set initial direction diff --git a/hooks/use-email-fetch.ts b/hooks/use-email-fetch.ts index 3a4cb2cf..5e9c96e0 100644 --- a/hooks/use-email-fetch.ts +++ b/hooks/use-email-fetch.ts @@ -2,7 +2,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'; import { useToast } from './use-toast'; import { EmailMessage, EmailContent } from '@/types/email'; import { detectTextDirection } from '@/lib/utils/text-direction'; -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import { sanitizeHtml } from '@/lib/utils/email-utils'; interface EmailFetchState { email: EmailMessage | null; diff --git a/lib/server/email-parser.ts b/lib/server/email-parser.ts index 305e7605..c79a50f8 100644 --- a/lib/server/email-parser.ts +++ b/lib/server/email-parser.ts @@ -1,4 +1,4 @@ -import { sanitizeHtml } from '@/lib/utils/dom-sanitizer'; +import { sanitizeHtml } from '@/lib/utils/email-formatter'; import { simpleParser } from 'mailparser'; function getAddressText(addresses: any): string | null { diff --git a/lib/utils/dom-sanitizer.ts b/lib/utils/dom-sanitizer.ts deleted file mode 100644 index cfd848b2..00000000 --- a/lib/utils/dom-sanitizer.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * DOM Sanitizer - * - * Centralized DOMPurify configuration for consistent HTML sanitization - * throughout the application. This ensures all sanitized content follows - * the same rules for security and presentation. - */ - -import DOMPurify from 'isomorphic-dompurify'; - -// Reset any existing hooks to start with a clean slate -DOMPurify.removeAllHooks(); - -// Configure DOMPurify with settings appropriate for email content -DOMPurify.setConfig({ - // Allow these attributes on all elements - ADD_ATTR: [ - 'dir', // For text direction - 'lang', // For language specification - 'style', // For inline styles (carefully sanitized) - 'class', 'id', // For CSS targeting - 'title', // For tooltips - 'target', 'rel', // For links - 'colspan', 'rowspan', // For tables - 'width', 'height', 'align', 'valign', // Basic layout - 'alt', 'src', // For images - 'href', // For links - 'data-*' // For custom data attributes - ], - - // Allow these HTML tags - ADD_TAGS: [ - 'html', 'head', 'body', 'style', 'link', 'meta', 'title', - 'table', 'caption', 'col', 'colgroup', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', - 'div', 'span', 'img', 'br', 'hr', 'section', 'article', 'header', 'footer', - 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'blockquote', 'pre', 'code', - 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'a', 'b', 'i', 'u', 'em', - 'strong', 'del', 'ins', 'mark', 'small', 'sub', 'sup', 'q', 'abbr' - ], - - // Explicitly forbid these dangerous tags - FORBID_TAGS: [ - 'script', 'iframe', 'object', 'embed', 'form', - 'input', 'button', 'select', 'textarea' - ], - - // Explicitly forbid these dangerous attributes - FORBID_ATTR: [ - 'onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout', - 'onkeydown', 'onkeypress', 'onkeyup', 'onchange' - ], - - // Other configuration options - KEEP_CONTENT: true, // Keep content of removed tags - WHOLE_DOCUMENT: false, // Don't require a full HTML document - ALLOW_DATA_ATTR: true, // Allow data-* attributes - ALLOW_UNKNOWN_PROTOCOLS: true, // Allow protocols like cid: for email images - FORCE_BODY: false // Don't force content to be wrapped in -}); - -// Export a wrapped sanitizeHtml function that handles email-specific fixes -export function sanitizeHtml(html: string): string { - if (!html) return ''; - - try { - // Use DOMPurify with our configured settings - const clean = DOMPurify.sanitize(html); - - // Fix common email rendering issues - return clean - // Fix for Outlook WebVML content - .replace(/