Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSMTPTransportSendBuildsHeadersForValidInput(t *testing.T) {
|
||||
transport := newSMTPTransport("smtp.example.com", "587", "user", "pass")
|
||||
|
||||
var captured string
|
||||
called := false
|
||||
prev := smtpSendMail
|
||||
smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
|
||||
called = true
|
||||
if addr != "smtp.example.com:587" {
|
||||
t.Fatalf("addr=%q", addr)
|
||||
}
|
||||
if from != "sender@example.com" {
|
||||
t.Fatalf("from=%q", from)
|
||||
}
|
||||
if len(to) != 1 || to[0] != "recipient@example.com" {
|
||||
t.Fatalf("to=%v", to)
|
||||
}
|
||||
captured = string(msg)
|
||||
return nil
|
||||
}
|
||||
t.Cleanup(func() { smtpSendMail = prev })
|
||||
|
||||
err := transport.Send(context.Background(), FromIdentity{
|
||||
Email: "sender@example.com",
|
||||
Name: "Descrybe Team",
|
||||
ReplyTo: "reply@example.com",
|
||||
}, Outbound{
|
||||
To: "recipient@example.com",
|
||||
Subject: "Hello there",
|
||||
Text: "plain body",
|
||||
HTML: "<p>html body</p>",
|
||||
Headers: map[string]string{"List-Unsubscribe": "<https://example.com/unsub>"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !called {
|
||||
t.Fatal("expected smtpSendMail to be called")
|
||||
}
|
||||
for _, want := range []string{
|
||||
"From: Descrybe Team <sender@example.com>",
|
||||
"To: recipient@example.com",
|
||||
"Subject: Hello there",
|
||||
"Reply-To: reply@example.com",
|
||||
"List-Unsubscribe: <https://example.com/unsub>",
|
||||
} {
|
||||
if !strings.Contains(captured, want) {
|
||||
t.Fatalf("message missing %q:\n%s", want, captured)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMTPTransportSendRejectsHeaderInjection(t *testing.T) {
|
||||
cases := []Outbound{
|
||||
{To: "recipient@example.com", Subject: "ok\r\nBcc:evil@example.com", Text: "body"},
|
||||
{To: "recipient@example.com", Subject: "ok", Text: "body", Headers: map[string]string{"X-Test\r\nBcc": "1"}},
|
||||
{To: "recipient@example.com", Subject: "ok", Text: "body", Headers: map[string]string{"X-Test": "1\r\nBcc:evil@example.com"}},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
transport := newSMTPTransport("smtp.example.com", "587", "", "")
|
||||
called := false
|
||||
prev := smtpSendMail
|
||||
smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
|
||||
called = true
|
||||
return nil
|
||||
}
|
||||
|
||||
err := transport.Send(context.Background(), FromIdentity{
|
||||
Email: "sender@example.com",
|
||||
ReplyTo: "reply@example.com",
|
||||
}, tc)
|
||||
smtpSendMail = prev
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for %#v", tc)
|
||||
}
|
||||
if called {
|
||||
t.Fatalf("smtpSendMail should not be called for %#v", tc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMTPTransportSendRejectsReplyToInjection(t *testing.T) {
|
||||
transport := newSMTPTransport("smtp.example.com", "587", "", "")
|
||||
|
||||
called := false
|
||||
prev := smtpSendMail
|
||||
smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
|
||||
called = true
|
||||
return nil
|
||||
}
|
||||
t.Cleanup(func() { smtpSendMail = prev })
|
||||
|
||||
err := transport.Send(context.Background(), FromIdentity{
|
||||
Email: "sender@example.com",
|
||||
ReplyTo: "reply@example.com\r\nBcc:evil@example.com",
|
||||
}, Outbound{
|
||||
To: "recipient@example.com",
|
||||
Subject: "safe",
|
||||
Text: "body",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected invalid reply-to error")
|
||||
}
|
||||
if called {
|
||||
t.Fatal("smtpSendMail should not be called")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user