diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx index 9ebb861b..573acbf3 100644 --- a/components/email/email-viewer.tsx +++ b/components/email/email-viewer.tsx @@ -3,7 +3,7 @@ import { useState, useEffect, useLayoutEffect, useMemo, useRef, useCallback } from "react"; import DOMPurify from "dompurify"; import { Email, ContactCard, Mailbox } from "@/lib/jmap/types"; -import { EMAIL_IFRAME_SANITIZE_CONFIG, collapseBlockedImageContainers, plainTextToSafeHtml } from "@/lib/email-sanitization"; +import { EMAIL_IFRAME_SANITIZE_CONFIG, collapseBlockedImageContainers, escapeHtml, plainTextToSafeHtml, sanitizeEmailHtml } from "@/lib/email-sanitization"; import { hasMeaningfulHtmlBody } from "@/lib/signature-utils"; import { Button } from "@/components/ui/button"; import { Avatar } from "@/components/ui/avatar"; @@ -3066,14 +3066,26 @@ export function EmailViewer({ if (!email) return; const printSender = email.from?.[0]; const date = email.sentAt ? formatDateTime(email.sentAt, timeFormat, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' }) : ''; - const toList = email.to?.map(r => r.name ? `${r.name} <${r.email}>` : r.email).join(', ') || ''; - const ccList = email.cc?.map(r => r.name ? `${r.name} <${r.email}>` : r.email).join(', ') || ''; + const formatRecipient = (r: { name?: string | null; email: string }) => + r.name ? `${escapeHtml(r.name)} <${escapeHtml(r.email)}>` : escapeHtml(r.email); + const toList = email.to?.map(formatRecipient).join(', ') || ''; + const ccList = email.cc?.map(formatRecipient).join(', ') || ''; + const subjectText = email.subject || t('no_subject'); + const senderText = printSender?.name + ? `${printSender.name} <${printSender.email}>` + : printSender?.email || t('unknown_sender'); + // The body was sanitized with EMAIL_IFRAME_SANITIZE_CONFIG which permits + //
-
${DOMPurify.sanitize(email.subject || t('no_subject'))}
+
${escapeHtml(subjectText)}
-
${t('from')}: ${DOMPurify.sanitize(printSender?.name ? `${printSender.name} <${printSender.email}>` : printSender?.email || t('unknown_sender'))}
- ${toList ? `
${t('to')}: ${toList}
` : ''} +
${escapeHtml(t('from'))}: ${escapeHtml(senderText)}
+ ${toList ? `
${escapeHtml(t('to'))}: ${toList}
` : ''} ${ccList ? `
CC: ${ccList}
` : ''} - ${date ? `
${t('date')}: ${DOMPurify.sanitize(date)}
` : ''} + ${date ? `
${escapeHtml(t('date'))}: ${escapeHtml(date)}
` : ''}
-
${effectiveEmailContent.html}
+
${printableBody}
`); printWindow.document.close(); printWindow.focus(); diff --git a/lib/email-sanitization.ts b/lib/email-sanitization.ts index 20145f55..c48c06bd 100644 --- a/lib/email-sanitization.ts +++ b/lib/email-sanitization.ts @@ -131,7 +131,7 @@ const HTML_ESCAPES: Record = { "'": ''', }; -function escapeHtml(str: string): string { +export function escapeHtml(str: string): string { return str.replace(/[&<>"']/g, (c) => HTML_ESCAPES[c]); }