114 lines
3 KiB
Go
114 lines
3 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// Rule returns the single aggregation rule for this checker. It folds
|
|
// every finding produced by Collect into a CheckState whose status is
|
|
// the worst severity seen.
|
|
func Rule() sdk.CheckRule {
|
|
return &emailKeyRule{}
|
|
}
|
|
|
|
type emailKeyRule struct{}
|
|
|
|
func (r *emailKeyRule) Name() string { return "openpgpkey_smimea_check" }
|
|
|
|
func (r *emailKeyRule) Description() string {
|
|
return "Validates a DNS-published OpenPGP key (RFC 7929) or S/MIME certificate (RFC 8162), running DNSSEC, record-hash, parse, expiration, algorithm-strength, and S/MIME EKU checks."
|
|
}
|
|
|
|
func (r *emailKeyRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
var data EmailKeyData
|
|
if err := obs.Get(ctx, ObservationKey, &data); err != nil {
|
|
return []sdk.CheckState{{
|
|
Status: sdk.StatusError,
|
|
Message: fmt.Sprintf("Failed to read observation %q: %v", ObservationKey, err),
|
|
Code: "openpgpkey_observation_error",
|
|
}}
|
|
}
|
|
return []sdk.CheckState{evaluate(&data)}
|
|
}
|
|
|
|
// evaluate folds findings into a CheckState. The status is the highest
|
|
// severity observed: any Crit makes the whole result Crit, any Warn
|
|
// makes it Warn, otherwise Info/OK.
|
|
func evaluate(data *EmailKeyData) sdk.CheckState {
|
|
var crit, warn, info int
|
|
var firstCrit, firstWarn, firstInfo string
|
|
for _, f := range data.Findings {
|
|
switch f.Severity {
|
|
case SeverityCrit:
|
|
crit++
|
|
if firstCrit == "" {
|
|
firstCrit = f.Message
|
|
}
|
|
case SeverityWarn:
|
|
warn++
|
|
if firstWarn == "" {
|
|
firstWarn = f.Message
|
|
}
|
|
case SeverityInfo:
|
|
info++
|
|
if firstInfo == "" {
|
|
firstInfo = f.Message
|
|
}
|
|
}
|
|
}
|
|
|
|
status := sdk.StatusOK
|
|
msg := summariseHealthy(data)
|
|
code := "openpgpkey_ok"
|
|
switch {
|
|
case crit > 0:
|
|
status = sdk.StatusCrit
|
|
msg = firstCrit
|
|
code = "openpgpkey_crit"
|
|
case warn > 0:
|
|
status = sdk.StatusWarn
|
|
msg = firstWarn
|
|
code = "openpgpkey_warn"
|
|
case info > 0:
|
|
status = sdk.StatusInfo
|
|
msg = firstInfo
|
|
code = "openpgpkey_info"
|
|
}
|
|
|
|
meta := map[string]any{
|
|
"kind": data.Kind,
|
|
"queried": data.QueriedOwner,
|
|
"record_count": data.RecordCount,
|
|
"findings": data.Findings,
|
|
}
|
|
if data.DNSSECSecure != nil {
|
|
meta["dnssec_secure"] = *data.DNSSECSecure
|
|
}
|
|
|
|
return sdk.CheckState{
|
|
Status: status,
|
|
Message: msg,
|
|
Code: code,
|
|
Subject: data.QueriedOwner,
|
|
Meta: meta,
|
|
}
|
|
}
|
|
|
|
func summariseHealthy(data *EmailKeyData) string {
|
|
switch data.Kind {
|
|
case KindOpenPGPKey:
|
|
if data.OpenPGP != nil && data.OpenPGP.Fingerprint != "" {
|
|
return fmt.Sprintf("OPENPGPKEY %s published and valid (fingerprint %s)", data.QueriedOwner, data.OpenPGP.Fingerprint)
|
|
}
|
|
return fmt.Sprintf("OPENPGPKEY %s published and valid", data.QueriedOwner)
|
|
case KindSMIMEA:
|
|
if data.SMIMEA != nil && data.SMIMEA.Certificate != nil {
|
|
return fmt.Sprintf("SMIMEA %s valid (subject %s)", data.QueriedOwner, data.SMIMEA.Certificate.Subject)
|
|
}
|
|
return fmt.Sprintf("SMIMEA %s published and valid", data.QueriedOwner)
|
|
}
|
|
return "Record validated"
|
|
}
|