ultisuite-client/lib/mail-remote-content.ts
2026-05-25 13:52:40 +02:00

52 lines
1.6 KiB
TypeScript

/** Détecte les ressources distantes dans le HTML d'un mail. */
const REMOTE_RESOURCE_ATTR =
/\s(?:src|srcset|data-src|data-original|data-srcset|poster|background|data)\s*=\s*["']?(?:https?:\/\/|\/\/)/i
const RELATIVE_RESOURCE_ATTR =
/\s(?:src|srcset|data-src|data-original|href|background|poster)\s*=\s*["'](?!https?:|\/\/|data:|cid:|mailto:|#|javascript:)([^"']+)["']/i
const REMOTE_LINK_STYLESHEET =
/<link[^>]+href\s*=\s*["']?(?:https?:\/\/|\/\/)/i
const CSS_REMOTE_URL = /url\s*\(\s*['"]?(?:https?:\/\/|\/\/|[^'"data:#][^'")]*)/i
export function htmlHasRemoteContent(html: string): boolean {
if (!html?.trim()) return false
const hasRemoteSignals =
REMOTE_RESOURCE_ATTR.test(html) ||
RELATIVE_RESOURCE_ATTR.test(html) ||
REMOTE_LINK_STYLESHEET.test(html) ||
CSS_REMOTE_URL.test(html)
if (hasRemoteSignals) return true
if (/<!DOCTYPE|<html[\s>]/i.test(html)) {
return (
/<img\b/i.test(html) ||
/<link[^>]+rel=["']?stylesheet/i.test(html) ||
/<style\b/i.test(html)
)
}
return false
}
export function buildEmailPreviewCsp(blockRemoteContent: boolean): string {
if (blockRemoteContent) {
return "default-src 'none'; style-src 'unsafe-inline'; img-src data: blob:;"
}
return [
"default-src 'none'",
"style-src 'unsafe-inline' https: http:",
"style-src-elem 'unsafe-inline' https: http:",
// url() in style="" (Gmail signatures often use background-image on table cells)
"style-src-attr 'unsafe-inline' https: http:",
"img-src https: http: data: blob: cid:",
"font-src https: http: data:",
"media-src https: http:",
"child-src https: http:",
].join("; ")
}