Files
summercms/modules/postcard/templates_test.go
Jakub Zych 5e50b166ef refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
2026-09-28 02:21:02 +02:00

129 lines
4.2 KiB
Go

package postcard
import (
"context"
"strings"
"testing"
"testing/fstest"
)
func TestMailRecipientsAndSafety(t *testing.T) {
t.Parallel()
fsys := fstest.MapFS{
"views/mail/hello.htm": {Data: []byte(`subject = "Witaj {{ .Name }}"
layout = "default"
==
Witaj **{{ .Name }}**.
[Strona]({{ .URL }})
`)},
}
cat := NewCatalog()
if err := cat.Register("golem15.hello", fsys, []string{"golem15.hello::mail.hello"}, nil); err != nil {
t.Fatal(err)
}
drv := NewMemoryDriver()
mail := NewMailer(cat, drv, Options{From: "from@example.test"})
ctx := context.Background()
if err := mail.Send(ctx, Message{
Template: "golem15.hello::mail.hello",
To: []string{"ada@example.test"},
Cc: []string{"cc@example.test"},
Bcc: []string{"bcc@example.test"},
ReplyTo: "reply@example.test",
Vars: map[string]any{"Name": "Ada", "URL": "https://example.test"},
}); err != nil {
t.Fatal(err)
}
got := drv.Messages()
if len(got) != 1 {
t.Fatalf("stored %d messages", len(got))
}
msg := got[0]
if len(msg.To) != 1 || msg.To[0] != "ada@example.test" {
t.Fatalf("To = %v", msg.To)
}
if len(msg.Cc) != 1 || msg.Cc[0] != "cc@example.test" {
t.Fatalf("Cc = %v", msg.Cc)
}
if len(msg.Bcc) != 1 || msg.Bcc[0] != "bcc@example.test" {
t.Fatalf("Bcc = %v", msg.Bcc)
}
if msg.ReplyTo != "reply@example.test" {
t.Fatalf("ReplyTo = %q", msg.ReplyTo)
}
if msg.Subject != "Witaj Ada" {
t.Fatalf("subject = %q", msg.Subject)
}
if !strings.Contains(msg.Text, "Witaj **Ada**.") {
t.Fatalf("text = %q", msg.Text)
}
if !strings.Contains(msg.HTML, "<strong>Ada</strong>") || !strings.Contains(msg.HTML, `href="https://example.test"`) {
t.Fatalf("html = %q", msg.HTML)
}
t.Run("raw tags markdown links and dangerous urls stay out of html", func(t *testing.T) {
cases := []map[string]any{
{"Name": `<script>alert(1)</script>`, "URL": "https://example.test"},
{"Name": "Ada", "URL": "javascript:alert(1)"},
{"Name": "Ada", "URL": "vbscript:msgbox(1)"},
{"Name": "Ada", "URL": "data:text/html;base64,PGh0bWw+"},
{"Name": `<iframe src="https://evil.test"></iframe>`, "URL": "https://example.test"},
}
for _, vars := range cases {
drv := NewMemoryDriver()
mail := NewMailer(cat, drv, Options{From: "from@example.test"})
err := mail.Send(ctx, Message{
Template: "golem15.hello::mail.hello",
To: []string{"ada@example.test"},
Vars: vars,
})
if err != nil {
if strings.Contains(err.Error(), "unsafe") || strings.Contains(err.Error(), "dangerous") {
continue
}
t.Fatalf("unexpected send error for %v: %v", vars, err)
}
html := strings.ToLower(drv.Messages()[0].HTML)
for _, banned := range []string{"<script", "<iframe", "javascript:", "vbscript:", "data:text/html"} {
if strings.Contains(html, banned) {
t.Fatalf("unsafe %q leaked for %v:\n%s", banned, vars, html)
}
}
}
})
}
func TestMailRegistrationBoundaries(t *testing.T) {
t.Parallel()
t.Run("reserved default alias", func(t *testing.T) {
err := NewCatalog().Register("golem15.hello", fstest.MapFS{}, nil, map[string]string{
"default": "golem15.hello::mail.layouts.default",
})
if err == nil || !strings.Contains(err.Error(), "reserved") {
t.Fatalf("reserved alias error = %v", err)
}
})
t.Run("template not owned by plugin", func(t *testing.T) {
err := NewCatalog().Register("golem15.hello", fstest.MapFS{}, []string{"golem15.other::mail.hello"}, nil)
if err == nil || !strings.Contains(err.Error(), "golem15.hello") || !strings.Contains(err.Error(), "golem15.other::mail.hello") {
t.Fatalf("ownership error = %v", err)
}
})
t.Run("invalid dotted name", func(t *testing.T) {
err := NewCatalog().Register("golem15.hello", fstest.MapFS{}, []string{"golem15.hello::mail.hello/../x"}, nil)
if err == nil || !strings.Contains(err.Error(), "invalid mail name") {
t.Fatalf("invalid name error = %v", err)
}
})
t.Run("missing template names plugin and dotted name", func(t *testing.T) {
err := NewCatalog().Register("golem15.hello", fstest.MapFS{}, []string{"golem15.hello::mail.missing"}, nil)
if err == nil || !strings.Contains(err.Error(), "golem15.hello::mail.missing") {
t.Fatalf("missing template error = %v", err)
}
})
}