Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
101 lines
3.7 KiB
Go
101 lines
3.7 KiB
Go
package usecase
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"lambdamail/protocols/internal/application/port"
|
|
"lambdamail/protocols/internal/domain/valueobject"
|
|
)
|
|
|
|
type fakeTrusted struct {
|
|
trusted map[string]bool
|
|
err error
|
|
}
|
|
|
|
func (f *fakeTrusted) IsTrusted(_ context.Context, _ uuid.UUID, address string) (bool, error) {
|
|
return f.trusted[address], f.err
|
|
}
|
|
|
|
func deliverAsSpam(t *testing.T, trusted port.TrustedSenders, auth port.InboundAuthResult, envelope string) string {
|
|
t.Helper()
|
|
repo := &recordingMessageRepository{}
|
|
uc := NewProcessInboundEmailUseCase(nil, &capturingBlobStorage{}, repo)
|
|
uc.SetScanner(&stubScanner{result: &valueobject.ScanResult{Verdict: valueobject.ScanVerdictSpamJunk}})
|
|
uc.SetAuthenticator(&stubAuthenticator{result: auth})
|
|
if trusted != nil {
|
|
uc.SetTrustedSenders(trusted)
|
|
}
|
|
err := uc.Handle(context.Background(), ProcessInboundEmailInput{
|
|
Sender: envelope,
|
|
Recipients: []port.MailboxRecord{{ID: uuid.New()}},
|
|
RecipientAddresses: []string{"me@example.test"},
|
|
Body: bytes.NewBufferString("From: Jenny <Jenny@Friend.test>\r\nSubject: re: hi\r\n\r\nbody"),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Handle: %v", err)
|
|
}
|
|
return repo.persisted[0].TargetFolderName
|
|
}
|
|
|
|
var passDMARC = port.InboundAuthResult{SPF: "pass", DKIM: "pass", DMARC: "pass"}
|
|
|
|
func TestTrustedSenderIsNotFiledAsSpam(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"jenny@friend.test": true}}
|
|
if got := deliverAsSpam(t, trusted, passDMARC, "jenny@friend.test"); got != "INBOX" {
|
|
t.Fatalf("a trusted, authenticated sender was filed in %q", got)
|
|
}
|
|
}
|
|
|
|
func TestUntrustedSenderStillGoesToJunk(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"someone@else.test": true}}
|
|
if got := deliverAsSpam(t, trusted, passDMARC, "jenny@friend.test"); got != "Junk" {
|
|
t.Fatalf("an untrusted sender was filed in %q", got)
|
|
}
|
|
}
|
|
|
|
// Writing a contact's address in From is all a spammer needs to do, so trust
|
|
// only counts when the message proves it came from there.
|
|
func TestForgedTrustedSenderStillGoesToJunk(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"jenny@friend.test": true}}
|
|
forged := port.InboundAuthResult{SPF: "fail", DKIM: "none", DMARC: "fail"}
|
|
if got := deliverAsSpam(t, trusted, forged, "bounce@spammer.test"); got != "Junk" {
|
|
t.Fatalf("a forged From reached the inbox: %q", got)
|
|
}
|
|
}
|
|
|
|
// SPF that passed for the spammer's own domain proves nothing about From.
|
|
func TestSPFForAnotherDomainDoesNotProveFrom(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"jenny@friend.test": true}}
|
|
other := port.InboundAuthResult{SPF: "pass", DKIM: "none", DMARC: "none"}
|
|
if got := deliverAsSpam(t, trusted, other, "bounce@spammer.test"); got != "Junk" {
|
|
t.Fatalf("SPF for a different domain let a forged From in: %q", got)
|
|
}
|
|
}
|
|
|
|
// A domain with no DMARC record can still be proven by SPF for its own domain.
|
|
func TestSPFForTheSameDomainProvesFrom(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"jenny@friend.test": true}}
|
|
spfOnly := port.InboundAuthResult{SPF: "pass", DKIM: "none", DMARC: "none"}
|
|
if got := deliverAsSpam(t, trusted, spfOnly, "mailer@friend.test"); got != "INBOX" {
|
|
t.Fatalf("SPF for the sender's own domain was not accepted: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestLookupFailureLeavesTheMessageInJunk(t *testing.T) {
|
|
trusted := &fakeTrusted{trusted: map[string]bool{"jenny@friend.test": true}, err: errors.New("db down")}
|
|
if got := deliverAsSpam(t, trusted, passDMARC, "jenny@friend.test"); got != "Junk" {
|
|
t.Fatalf("a failed lookup let mail through: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestWithoutTrustedSendersSpamGoesToJunk(t *testing.T) {
|
|
if got := deliverAsSpam(t, nil, passDMARC, "jenny@friend.test"); got != "Junk" {
|
|
t.Fatalf("filed in %q", got)
|
|
}
|
|
}
|