ultisuite-backend/internal/mail/sanitize/email_policy.go
R3D347HR4Y cd0a80f5e8 huhu
2026-05-25 13:52:27 +02:00

60 lines
2.1 KiB
Go

package sanitize
import (
"regexp"
"github.com/microcosm-cc/bluemonday"
)
var (
styleType = regexp.MustCompile(`(?i)^text\/css$`)
cssJSURL = regexp.MustCompile(`(?i)url\s*\(\s*['"]?javascript:[^)]*\)`)
)
// emailPolicy preserves HTML email layout (inline styles, <style>, tables) while
// stripping scripts and event handlers. Display happens in a sandboxed iframe.
func emailPolicy() *bluemonday.Policy {
p := bluemonday.UGCPolicy()
// Full documents and email structure
p.AllowElements("html", "head", "body", "title")
p.AllowElements("font", "main", "nav", "header", "footer")
// Inline styles + <style> blocks (requires AllowUnsafe for tag content)
p.AllowAttrs("type").Matching(styleType).OnElements("style")
p.AllowAttrs("style").Globally()
p.AllowStyling()
p.AllowUnsafe(true)
p.AllowElementsContent("style")
// Legacy table / font attributes common in newsletters
p.AllowAttrs("bgcolor", "color").OnElements("basefont", "font", "hr", "td", "table", "tr", "th")
p.AllowAttrs("border").Matching(bluemonday.Integer).OnElements("img", "table")
p.AllowAttrs("cellpadding", "cellspacing").Matching(bluemonday.Integer).OnElements("table")
p.AllowAttrs("width", "height", "align", "valign", "background", "colspan", "rowspan").
OnElements("table", "tbody", "tr", "td", "th", "thead", "tfoot", "colgroup", "col", "div", "p", "img")
// External CSS (resolved by the client when remote content is allowed)
p.AllowAttrs("rel", "href").OnElements("link")
p.AllowAttrs("type").Matching(styleType).OnElements("link")
p.AllowRelativeURLs(true)
p.AllowDataURIImages()
p.AllowURLSchemes("cid")
// Lazy-load / responsive images common in newsletters
p.AllowAttrs("srcset").OnElements("img", "source")
p.AllowAttrs("loading", "decoding", "sizes").OnElements("img", "source")
p.AllowAttrs(
"data-src", "data-original", "data-lazy-src", "data-srcset",
"data-href", "data-url", "data-image", "data-bg",
).OnElements("img", "source")
return p
}
var policy = emailPolicy()
func stripUnsafeCSSURLs(html string) string {
return cssJSURL.ReplaceAllString(html, "url(about:blank)")
}