package handlers import ( "net/http" "testing" "time" "github.com/mixeme/selfpost/internal/dmarc" "github.com/mixeme/selfpost/internal/store" ) // The DMARC pages, rendered from the real stores and the handlers. Their markup // is held to the mockups by the guards in internal/web/view; what is checked // here is that the handlers fill the typed pages from what is stored and that // each page reaches only what its viewer may see. // dmarcStand is a panel with report ingest on and one report stored for the // stand's domain: a relay that passed and a source that failed both checks. type dmarcStand struct { appStand reportID int64 } func newDMARCStand(t *testing.T) dmarcStand { t.Helper() s := dmarcStand{appStand: newAppStand(t)} s.h.cfg.DMARCEnabled, s.h.cfg.Hostname = true, "mail.example.org" s.h.dmarc = dmarc.NewService(s.h.store, nil, "mail.example.org", true) received := time.Now().UTC().Add(-2 * time.Hour) id, err := s.h.store.InsertDMARCReport(store.DMARCReport{ Domain: "example.org", Reporter: "Outlook.com", ReportID: "5f1c9a0e7b2d4e61a3", PeriodBegin: received.Add(-30 * time.Hour), PeriodEnd: received.Add(-6 * time.Hour), ReceivedAt: received, ContactEmail: "noreply-dmarc@outlook.example", PolicyP: "none", PolicySP: "none", PolicyPct: 100, PolicyADKIM: "r", PolicyASPF: "r", PassCount: 1903, FailCount: 7, Recipient: "dmarc-reports@mail.example.org", Records: []store.DMARCReportRecord{ {SourceIP: "203.0.113.25", Count: 1903, Disposition: "none", SPFResult: "pass", DKIMResult: "pass", HeaderFrom: "example.org"}, {SourceIP: "198.51.100.44", Count: 7, Disposition: "none", SPFResult: "fail", DKIMResult: "fail", HeaderFrom: "example.org"}, }, }) if err != nil { t.Fatalf("InsertDMARCReport: %v", err) } s.reportID = id return s } func TestDMARCHubShowsIngestAndRecentReports(t *testing.T) { s := newDMARCStand(t) body := getBody(t, s.h.HandleDMARCList, "/outbound/dmarc") has(t, "hub", body, `

DMARC reports

`, `

Ingest

`, `ok`, `1 kept · 0 parse failures`, `Hosted addresses`, `dmarc-reports+<domain>@mail.example.org`, `500 reports a domain or 90 days`, `

Recent reports

`, `example.org`, `Outlook.com`, "1\u00a0903", `7`, `href="/outbound/dmarc/reports/`+idStr(s.reportID)+`">View`) lacks(t, "hub", body, `None yet`) } // Before the first report the page says how to get one rather than showing an // empty table next to a healthy-looking stamp. func TestDMARCHubBeforeTheFirstReport(t *testing.T) { s := newAppStand(t) s.h.cfg.DMARCEnabled, s.h.cfg.Hostname = true, "mail.example.org" s.h.dmarc = dmarc.NewService(s.h.store, nil, "mail.example.org", true) body := getBody(t, s.h.HandleDMARCList, "/outbound/dmarc") has(t, "hub", body, `quiet`, `None yet`, `rua=`, `publish MX for mail.example.org`, `No reports yet.`) lacks(t, "hub", body, `alert(1)`, ReportID: `">`, PeriodBegin: time.Now().Add(-48 * time.Hour), PeriodEnd: time.Now().Add(-24 * time.Hour), ReceivedAt: time.Now(), ContactEmail: `">x`, PolicyP: `none`, PassCount: 1, FailCount: 1, Records: []store.DMARCReportRecord{{SourceIP: `1.2.3.4`, Count: 2, Disposition: `none`, SPFResult: `x`, DKIMResult: "fail", HeaderFrom: `

`}}, }) if err != nil { t.Fatal(err) } for name, body := range map[string]string{ "hub": getBody(t, s.h.HandleDMARCList, "/outbound/dmarc"), "domain": pageOf(t, s.h.HandleDMARCDomain, "/outbound/dmarc/domains/1"), "report": reportPage(t, s, id), } { lacks(t, name, body, `