mox/dmarcrpt/parse_test.go
Mechiel Lukkien cb229cb6cf
mox!
2023-01-30 14:27:06 +01:00

179 lines
4.2 KiB
Go

package dmarcrpt
import (
"os"
"reflect"
"strings"
"testing"
)
const reportExample = `<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<email>noreply-dmarc-support@google.com</email>
<extra_contact_info>https://support.google.com/a/answer/2466580</extra_contact_info>
<report_id>10051505501689795560</report_id>
<date_range>
<begin>1596412800</begin>
<end>1596499199</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.org</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>reject</p>
<sp>reject</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>127.0.0.1</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.org</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>example.org</domain>
<result>pass</result>
<selector>example</selector>
</dkim>
<spf>
<domain>example.org</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>
`
func TestParseReport(t *testing.T) {
var expect = &Feedback{
ReportMetadata: ReportMetadata{
OrgName: "google.com",
Email: "noreply-dmarc-support@google.com",
ExtraContactInfo: "https://support.google.com/a/answer/2466580",
ReportID: "10051505501689795560",
DateRange: DateRange{
Begin: 1596412800,
End: 1596499199,
},
},
PolicyPublished: PolicyPublished{
Domain: "example.org",
ADKIM: "r",
ASPF: "r",
Policy: "reject",
SubdomainPolicy: "reject",
Percentage: 100,
},
Records: []ReportRecord{
{
Row: Row{
SourceIP: "127.0.0.1",
Count: 1,
PolicyEvaluated: PolicyEvaluated{
Disposition: DispositionNone,
DKIM: DMARCPass,
SPF: DMARCPass,
},
},
Identifiers: Identifiers{
HeaderFrom: "example.org",
},
AuthResults: AuthResults{
DKIM: []DKIMAuthResult{
{
Domain: "example.org",
Result: DKIMPass,
Selector: "example",
},
},
SPF: []SPFAuthResult{
{
Domain: "example.org",
Result: SPFPass,
},
},
},
},
},
}
feedback, err := ParseReport(strings.NewReader(reportExample))
if err != nil {
t.Fatalf("parsing report: %s", err)
}
if !reflect.DeepEqual(expect, feedback) {
t.Fatalf("expected:\n%#v\ngot:\n%#v", expect, feedback)
}
}
func TestParseMessageReport(t *testing.T) {
const dir = "../testdata/dmarc-reports"
files, err := os.ReadDir(dir)
if err != nil {
t.Fatalf("listing dmarc report emails: %s", err)
}
for _, file := range files {
p := dir + "/" + file.Name()
f, err := os.Open(p)
if err != nil {
t.Fatalf("open %q: %s", p, err)
}
_, err = ParseMessageReport(f)
if err != nil {
t.Fatalf("ParseMessageReport: %q: %s", p, err)
}
f.Close()
}
// No report in a non-multipart message.
_, err = ParseMessageReport(strings.NewReader("From: <mjl@mox.example>\r\n\r\nNo report.\r\n"))
if err != ErrNoReport {
t.Fatalf("message without report, got err %#v, expected ErrNoreport", err)
}
// No report in a multipart message.
var multipartNoreport = strings.ReplaceAll(`From: <mjl@mox.example>
To: <mjl@mox.example>
Subject: Report Domain: mox.example Submitter: mail.mox.example
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="===============5735553800636657282=="
--===============5735553800636657282==
Content-Type: text/plain
MIME-Version: 1.0
test
--===============5735553800636657282==
Content-Type: text/html
MIME-Version: 1.0
<html></html>
--===============5735553800636657282==--
`, "\n", "\r\n")
_, err = ParseMessageReport(strings.NewReader(multipartNoreport))
if err != ErrNoReport {
t.Fatalf("message without report, got err %#v, expected ErrNoreport", err)
}
}
func FuzzParseReport(f *testing.F) {
f.Add("")
f.Add(reportExample)
f.Fuzz(func(t *testing.T, s string) {
ParseReport(strings.NewReader(s))
})
}