mirror of
https://github.com/mjl-/mox.git
synced 2025-01-14 01:06:27 +03:00
webadmin: in list with dmarc evaluations, add the dispositions applied
to easily spot rejects
This commit is contained in:
parent
bcb80c3598
commit
651fa68067
4 changed files with 41 additions and 22 deletions
|
@ -22,6 +22,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
@ -219,9 +220,10 @@ func Evaluations(ctx context.Context) ([]Evaluation, error) {
|
||||||
// EvaluationStat summarizes stored evaluations, for inclusion in an upcoming
|
// EvaluationStat summarizes stored evaluations, for inclusion in an upcoming
|
||||||
// aggregate report, for a domain.
|
// aggregate report, for a domain.
|
||||||
type EvaluationStat struct {
|
type EvaluationStat struct {
|
||||||
Count int
|
Domain dns.Domain
|
||||||
SendReport bool
|
Dispositions []string
|
||||||
Domain dns.Domain
|
Count int
|
||||||
|
SendReport bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvaluationStats returns evaluation counts and report-sending status per domain.
|
// EvaluationStats returns evaluation counts and report-sending status per domain.
|
||||||
|
@ -235,6 +237,9 @@ func EvaluationStats(ctx context.Context) (map[string]EvaluationStat, error) {
|
||||||
|
|
||||||
err = bstore.QueryDB[Evaluation](ctx, db).ForEach(func(e Evaluation) error {
|
err = bstore.QueryDB[Evaluation](ctx, db).ForEach(func(e Evaluation) error {
|
||||||
if stat, ok := r[e.PolicyDomain]; ok {
|
if stat, ok := r[e.PolicyDomain]; ok {
|
||||||
|
if !slices.Contains(stat.Dispositions, string(e.Disposition)) {
|
||||||
|
stat.Dispositions = append(stat.Dispositions, string(e.Disposition))
|
||||||
|
}
|
||||||
stat.Count++
|
stat.Count++
|
||||||
stat.SendReport = stat.SendReport || !e.Optional
|
stat.SendReport = stat.SendReport || !e.Optional
|
||||||
r[e.PolicyDomain] = stat
|
r[e.PolicyDomain] = stat
|
||||||
|
@ -244,9 +249,10 @@ func EvaluationStats(ctx context.Context) (map[string]EvaluationStat, error) {
|
||||||
return fmt.Errorf("parsing domain %q: %v", e.PolicyDomain, err)
|
return fmt.Errorf("parsing domain %q: %v", e.PolicyDomain, err)
|
||||||
}
|
}
|
||||||
r[e.PolicyDomain] = EvaluationStat{
|
r[e.PolicyDomain] = EvaluationStat{
|
||||||
Count: 1,
|
Domain: dom,
|
||||||
SendReport: !e.Optional,
|
Dispositions: []string{string(e.Disposition)},
|
||||||
Domain: dom,
|
Count: 1,
|
||||||
|
SendReport: !e.Optional,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -109,14 +109,16 @@ func TestEvaluations(t *testing.T) {
|
||||||
|
|
||||||
expStats := map[string]EvaluationStat{
|
expStats := map[string]EvaluationStat{
|
||||||
"sender1.example": {
|
"sender1.example": {
|
||||||
Count: 3,
|
Domain: dns.Domain{ASCII: "sender1.example"},
|
||||||
SendReport: true,
|
Dispositions: []string{"none"},
|
||||||
Domain: dns.Domain{ASCII: "sender1.example"},
|
Count: 3,
|
||||||
|
SendReport: true,
|
||||||
},
|
},
|
||||||
"sender2.example": {
|
"sender2.example": {
|
||||||
Count: 1,
|
Domain: dns.Domain{ASCII: "sender2.example"},
|
||||||
SendReport: true,
|
Dispositions: []string{"none"},
|
||||||
Domain: dns.Domain{ASCII: "sender2.example"},
|
Count: 1,
|
||||||
|
SendReport: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
stats, err := EvaluationStats(ctxbg)
|
stats, err := EvaluationStats(ctxbg)
|
||||||
|
@ -142,9 +144,10 @@ func TestEvaluations(t *testing.T) {
|
||||||
|
|
||||||
expStats = map[string]EvaluationStat{
|
expStats = map[string]EvaluationStat{
|
||||||
"sender2.example": {
|
"sender2.example": {
|
||||||
Count: 1,
|
Domain: dns.Domain{ASCII: "sender2.example"},
|
||||||
SendReport: true,
|
Dispositions: []string{"none"},
|
||||||
Domain: dns.Domain{ASCII: "sender2.example"},
|
Count: 1,
|
||||||
|
SendReport: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
stats, err = EvaluationStats(ctxbg)
|
stats, err = EvaluationStats(ctxbg)
|
||||||
|
|
|
@ -1112,6 +1112,7 @@ const dmarcEvaluations = async () => {
|
||||||
dom.thead(
|
dom.thead(
|
||||||
dom.tr(
|
dom.tr(
|
||||||
dom.th('Domain', attr({title: 'Domain in the message From header. Keep in mind these can be forged, so this does not necessarily mean someone from this domain authentically tried delivering email.'})),
|
dom.th('Domain', attr({title: 'Domain in the message From header. Keep in mind these can be forged, so this does not necessarily mean someone from this domain authentically tried delivering email.'})),
|
||||||
|
dom.th('Dispositions', attr({title: 'Unique dispositions occurring in report.'})),
|
||||||
dom.th('Evaluations', attr({title: 'Total number of message delivery attempts, including retries.'})),
|
dom.th('Evaluations', attr({title: 'Total number of message delivery attempts, including retries.'})),
|
||||||
dom.th('Send report', attr({title: 'Whether the current evaluations will cause a report to be sent.'})),
|
dom.th('Send report', attr({title: 'Whether the current evaluations will cause a report to be sent.'})),
|
||||||
),
|
),
|
||||||
|
@ -1120,6 +1121,7 @@ const dmarcEvaluations = async () => {
|
||||||
Object.entries(evalStats).sort((a, b) => a[0] < b[0] ? -1 : 1).map(t =>
|
Object.entries(evalStats).sort((a, b) => a[0] < b[0] ? -1 : 1).map(t =>
|
||||||
dom.tr(
|
dom.tr(
|
||||||
dom.td(dom.a(attr({href: '#dmarc/evaluations/'+domainName(t[1].Domain)}), domainString(t[1].Domain))),
|
dom.td(dom.a(attr({href: '#dmarc/evaluations/'+domainName(t[1].Domain)}), domainString(t[1].Domain))),
|
||||||
|
dom.td((t[1].Dispositions || []).join(' ')),
|
||||||
dom.td(style({textAlign: 'right'}), ''+t[1].Count),
|
dom.td(style({textAlign: 'right'}), ''+t[1].Count),
|
||||||
dom.td(style({textAlign: 'right'}), t[1].SendReport ? '✓' : ''),
|
dom.td(style({textAlign: 'right'}), t[1].SendReport ? '✓' : ''),
|
||||||
),
|
),
|
||||||
|
|
|
@ -3798,6 +3798,21 @@
|
||||||
"Name": "EvaluationStat",
|
"Name": "EvaluationStat",
|
||||||
"Docs": "EvaluationStat summarizes stored evaluations, for inclusion in an upcoming\naggregate report, for a domain.",
|
"Docs": "EvaluationStat summarizes stored evaluations, for inclusion in an upcoming\naggregate report, for a domain.",
|
||||||
"Fields": [
|
"Fields": [
|
||||||
|
{
|
||||||
|
"Name": "Domain",
|
||||||
|
"Docs": "",
|
||||||
|
"Typewords": [
|
||||||
|
"Domain"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Dispositions",
|
||||||
|
"Docs": "",
|
||||||
|
"Typewords": [
|
||||||
|
"[]",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Name": "Count",
|
"Name": "Count",
|
||||||
"Docs": "",
|
"Docs": "",
|
||||||
|
@ -3811,13 +3826,6 @@
|
||||||
"Typewords": [
|
"Typewords": [
|
||||||
"bool"
|
"bool"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "Domain",
|
|
||||||
"Docs": "",
|
|
||||||
"Typewords": [
|
|
||||||
"Domain"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue