mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
34c2dcd49d
and pass a logger to the message parser, so problems with message parsing get the cid logged.
183 lines
4.3 KiB
Go
183 lines
4.3 KiB
Go
package dmarcrpt
|
|
|
|
import (
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/mjl-/mox/mlog"
|
|
)
|
|
|
|
var xlog = mlog.New("dmarcrpt")
|
|
|
|
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(xlog, f)
|
|
if err != nil {
|
|
t.Fatalf("ParseMessageReport: %q: %s", p, err)
|
|
}
|
|
f.Close()
|
|
}
|
|
|
|
// No report in a non-multipart message.
|
|
_, err = ParseMessageReport(xlog, 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(xlog, 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))
|
|
})
|
|
}
|