/** * CENTRALIZED DOMPURIFY CONFIGURATION * * This file provides a consistent, centralized configuration for DOMPurify * used throughout the application. All components that need to sanitize HTML * should import from this file instead of configuring DOMPurify directly. */ import DOMPurify from 'isomorphic-dompurify'; // Reset any existing hooks to start with a clean slate DOMPurify.removeAllHooks(); /** * Configure DOMPurify with safe defaults for email content * This balances security with the need to display rich email content */ export function configureDOMPurify() { // Enhanced configuration for email content DOMPurify.setConfig({ ADD_TAGS: [ // SVG elements for simple charts/logos that might be in emails 'svg', 'path', 'g', 'circle', 'rect', 'line', 'polygon', 'ellipse', // Common email-specific elements 'o:p', 'font', // Allow comments for conditional HTML in emails '!--...--' ], ADD_ATTR: [ // SVG attributes 'viewbox', 'd', 'cx', 'cy', 'r', 'fill', 'stroke', 'stroke-width', 'x', 'y', 'width', 'height', // Additional HTML attributes commonly used in emails 'align', 'valign', 'bgcolor', 'color', 'cellpadding', 'cellspacing', 'colspan', 'rowspan', 'face', 'size', 'direction', 'role', 'aria-label', 'aria-hidden', // List attributes 'start', 'type', 'value', // Table attributes and styles 'border', 'frame', 'rules', 'summary', 'headers', 'scope', 'abbr', // Blockquote attributes 'cite', 'datetime', // Form elements attributes (read-only) 'readonly', 'disabled', 'selected', 'checked', 'multiple', 'wrap', // Additional attributes for forwarded emails 'style', 'class', 'id', 'dir', 'lang', 'title', // Table attributes commonly used in email clients 'background', 'bordercolor', 'width', 'height' ], FORBID_TAGS: [ // Remove dangerous tags 'script', 'object', 'iframe', 'embed', 'applet', 'meta', 'link', // Form elements that could be used for phishing 'form', 'button', 'input', 'textarea', 'select', 'option' ], FORBID_ATTR: [ // Remove JavaScript and dangerous attributes 'onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout', 'onmouseenter', 'onmouseleave', 'onkeydown', 'onkeypress', 'onkeyup', 'onchange', 'onsubmit', 'onreset', 'onselect', 'onblur', 'onfocus', 'onscroll', 'onbeforeunload', 'onunload', 'onhashchange', 'onpopstate', 'onpageshow', 'onpagehide', 'onabort', 'oncanplay', 'oncanplaythrough', 'ondurationchange', 'onemptied', 'onended', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onseeked', 'onseeking', 'onstalled', 'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting', 'animationend', 'animationiteration', 'animationstart', // Dangerous attributes 'formaction', 'xlink:href' ], ALLOW_DATA_ATTR: false, // Disable data-* attributes which can be used for XSS WHOLE_DOCUMENT: false, // Don't parse the entire document - just fragments SANITIZE_DOM: true, // Sanitize the DOM to prevent XSS KEEP_CONTENT: true, // Keep content of elements that are removed RETURN_DOM: false, // Return a DOM object rather than HTML string RETURN_DOM_FRAGMENT: false, // Return a DocumentFragment rather than HTML string FORCE_BODY: false, // Add a
tag if one doesn't exist ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp|data|irc):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i, ALLOW_UNKNOWN_PROTOCOLS: true, // Some email clients use custom protocols for images/attachments USE_PROFILES: { html: true } // Use the HTML profile for more permissive sanitization }); return DOMPurify; } // Singleton instance of configured DOMPurify for the app export const purify = configureDOMPurify(); /** * Sanitize HTML content using our email-specific configuration */ export function sanitizeHtml(content: string, options?: { preserveReplyFormat?: boolean }): string { if (!content) return ''; try { // Special handling for reply/forward emails to be less aggressive with sanitization const extraTags = options?.preserveReplyFormat ? ['style', 'blockquote', 'table', 'thead', 'tbody', 'tr', 'td', 'th'] : ['style']; const extraAttrs = options?.preserveReplyFormat ? ['style', 'class', 'align', 'valign', 'bgcolor', 'colspan', 'rowspan', 'width', 'height', 'border'] : ['style', 'class']; // Sanitize with our configured instance and options return purify.sanitize(content, { ADD_TAGS: extraTags, ADD_ATTR: extraAttrs }); } catch (error) { console.error('Failed to sanitize HTML content:', error); // Fallback to basic sanitization return content .replace(/