fix(mail): 优化邮件 HTML 与样式保留
Docker Release / Check web and api (push) Waiting to run
Docker Release / Resolve release tag (push) Blocked by required conditions
Docker Release / Build and publish all-in-one (push) Blocked by required conditions
Docker Release / Build and publish api (push) Blocked by required conditions
Docker Release / Build and publish web (push) Blocked by required conditions
Docker Release / Build and publish dovecot (push) Blocked by required conditions
Docker Release / Build and publish postfix (push) Blocked by required conditions
Docker Release / Build and publish rspamd (push) Blocked by required conditions
Docker Release / Create GitHub release (push) Blocked by required conditions
Docker Release / Check web and api (push) Waiting to run
Docker Release / Resolve release tag (push) Blocked by required conditions
Docker Release / Build and publish all-in-one (push) Blocked by required conditions
Docker Release / Build and publish api (push) Blocked by required conditions
Docker Release / Build and publish web (push) Blocked by required conditions
Docker Release / Build and publish dovecot (push) Blocked by required conditions
Docker Release / Build and publish postfix (push) Blocked by required conditions
Docker Release / Build and publish rspamd (push) Blocked by required conditions
Docker Release / Create GitHub release (push) Blocked by required conditions
- 支持整页邮件文档的清洗与渲染,保留 `<html>`、`<head>`、`<body>` 和 `<style>` 等结构。 - 提取并校验安全的邮件样式块,阻止包含外链、脚本式内容的 CSS。 - 补充 `dompurify` 类型声明以支持 `WHOLE_DOCUMENT` 配置。
This commit is contained in:
@@ -842,16 +842,21 @@ func TestCatchAllStoresUnregisteredMailForAdminOnly(t *testing.T) {
|
||||
|
||||
func TestHTMLPolicyPreservesEmailLayoutStyles(t *testing.T) {
|
||||
policy := NewHTMLPolicy()
|
||||
out := policy.Sanitize(`<div class="card" style="max-width:600px;margin:0 auto;background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 24px rgba(0,0,0,.12);color:#fff" onclick="alert(1)">
|
||||
out := policy.Sanitize(`<html><head><style type="text/css">.card{max-width:600px;margin:0 auto;background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 24px rgba(0,0,0,.12);color:#fff}.content{text-align:center;padding:24px}</style></head><body>
|
||||
<div class="card" style="max-width:600px;margin:0 auto;background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 24px rgba(0,0,0,.12);color:#fff" onclick="alert(1)">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse"><tr><td align="center" style="padding:24px;text-align:center;background-color:#f8fafc">
|
||||
<a href="javascript:alert(1)">bad</a><img src="x" onerror="alert(1)"><script>alert(1)</script>hello
|
||||
</td></tr></table>
|
||||
</div>`)
|
||||
for _, want := range []string{"class=\"card\"", "max-width: 600px", "margin: 0 auto", "background: linear-gradient", "box-shadow:", "cellpadding=\"0\"", "cellspacing=\"0\"", "align=\"center\"", "text-align: center"} {
|
||||
</div></body></html>`)
|
||||
for _, want := range []string{"<style type=\"text/css\">", ".card{", "class=\"card\"", "max-width: 600px", "margin: 0 auto", "background: linear-gradient", "box-shadow:", "cellpadding=\"0\"", "cellspacing=\"0\"", "align=\"center\"", "text-align: center"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("sanitized html missing %q: %s", want, out)
|
||||
}
|
||||
}
|
||||
blockedOut := policy.Sanitize(`<style>.bad{background:url(https://tracker.example/x);color:red}</style><p>ok</p>`)
|
||||
if strings.Contains(blockedOut, "<style") {
|
||||
t.Fatalf("unsafe css block should be removed: %s", blockedOut)
|
||||
}
|
||||
for _, blocked := range []string{"onclick", "onerror", "javascript:", "<script"} {
|
||||
if strings.Contains(strings.ToLower(out), blocked) {
|
||||
t.Fatalf("sanitized html kept unsafe %q: %s", blocked, out)
|
||||
|
||||
Reference in New Issue
Block a user