Files
sub2api/backend/internal/service/email_message_test.go
T
李建琦 6d655c9903
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
2026-08-21 18:30:13 +08:00

118 lines
4.1 KiB
Go

//go:build unit
package service
import (
"bytes"
"io"
"mime"
"mime/quotedprintable"
"net/mail"
"regexp"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestBuildSMTPMessageProducesStandardsCompliantMIME(t *testing.T) {
config := &SMTPConfig{
Host: "smtp.example.com",
From: "reply@example.com",
FromName: "Sub2API 通知",
}
body := "<html>\n<body>验证码:123456 &amp; ready</body>\n</html>"
message, err := buildSMTPMessage(config, "User <user@example.net>", "邮箱验证码", body)
require.NoError(t, err)
require.Equal(t, "reply@example.com", message.envelopeFrom)
require.Equal(t, "user@example.net", message.envelopeTo)
parsed, err := mail.ReadMessage(bytes.NewReader(message.data))
require.NoError(t, err)
from, err := mail.ParseAddress(parsed.Header.Get("From"))
require.NoError(t, err)
require.Equal(t, "Sub2API 通知", from.Name)
require.Equal(t, "reply@example.com", from.Address)
recipient, err := mail.ParseAddress(parsed.Header.Get("To"))
require.NoError(t, err)
require.Equal(t, "User", recipient.Name)
require.Equal(t, "user@example.net", recipient.Address)
decodedSubject, err := new(mime.WordDecoder).DecodeHeader(parsed.Header.Get("Subject"))
require.NoError(t, err)
require.Equal(t, "邮箱验证码", decodedSubject)
require.NotEmpty(t, parsed.Header.Get("Date"))
_, err = mail.ParseDate(parsed.Header.Get("Date"))
require.NoError(t, err)
require.Regexp(t, regexp.MustCompile(`^<[0-9a-f]{32}@example\.com>$`), parsed.Header.Get("Message-ID"))
require.Equal(t, "1.0", parsed.Header.Get("MIME-Version"))
require.Equal(t, "quoted-printable", parsed.Header.Get("Content-Transfer-Encoding"))
mediaType, params, err := mime.ParseMediaType(parsed.Header.Get("Content-Type"))
require.NoError(t, err)
require.Equal(t, "text/html", mediaType)
require.Equal(t, "UTF-8", params["charset"])
decodedBody, err := io.ReadAll(quotedprintable.NewReader(parsed.Body))
require.NoError(t, err)
require.Equal(t, strings.ReplaceAll(body, "\n", "\r\n"), string(decodedBody))
}
func TestBuildSMTPMessagePreventsHeaderInjection(t *testing.T) {
config := &SMTPConfig{
Host: "smtp.example.com",
From: "reply@example.com",
FromName: "Sender\r\nBcc: hidden@example.com",
}
message, err := buildSMTPMessage(config, "user@example.net", "Subject\r\nCc: hidden@example.com", "body")
require.NoError(t, err)
parsed, err := mail.ReadMessage(bytes.NewReader(message.data))
require.NoError(t, err)
require.Empty(t, parsed.Header.Get("Bcc"))
require.Empty(t, parsed.Header.Get("Cc"))
decodedSubject, err := new(mime.WordDecoder).DecodeHeader(parsed.Header.Get("Subject"))
require.NoError(t, err)
require.Equal(t, "SubjectCc: hidden@example.com", decodedSubject)
}
func TestBuildSMTPMessageRejectsInvalidConfiguration(t *testing.T) {
_, err := buildSMTPMessage(nil, "user@example.net", "subject", "body")
require.ErrorContains(t, err, "missing SMTP configuration")
_, err = buildSMTPMessage(&SMTPConfig{Host: "smtp.example.com"}, "user@example.net", "subject", "body")
require.ErrorContains(t, err, "invalid SMTP from address")
_, err = buildSMTPMessage(&SMTPConfig{
Host: "smtp.example.com",
From: "reply@example.com",
}, "invalid recipient <>", "subject", "body")
require.ErrorContains(t, err, "invalid SMTP recipient address")
_, err = buildSMTPMessage(&SMTPConfig{
Host: "smtp.example.com",
From: "reply@example.com",
}, "user@example.net\r\nBcc: hidden@example.net", "subject", "body")
require.ErrorContains(t, err, "invalid SMTP recipient address")
}
func TestBuildSMTPMessageUsesUniqueMessageIDs(t *testing.T) {
config := &SMTPConfig{Host: "smtp.example.com", From: "reply@example.com"}
first, err := buildSMTPMessage(config, "user@example.net", "subject", "body")
require.NoError(t, err)
second, err := buildSMTPMessage(config, "user@example.net", "subject", "body")
require.NoError(t, err)
firstParsed, err := mail.ReadMessage(bytes.NewReader(first.data))
require.NoError(t, err)
secondParsed, err := mail.ReadMessage(bytes.NewReader(second.data))
require.NoError(t, err)
require.NotEqual(t, firstParsed.Header.Get("Message-ID"), secondParsed.Header.Get("Message-ID"))
}