Initial commit
This commit is contained in:
commit
a2a7921cb8
20 changed files with 1868 additions and 0 deletions
89
checker/collect.go
Normal file
89
checker/collect.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package checker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
// serviceType is the happyDomain service type string this checker binds to.
|
||||
const serviceType = "svcs.CAAPolicy"
|
||||
|
||||
// serviceMessage is a local copy of happydns.ServiceMessage to avoid
|
||||
// depending on the happyDomain core repository.
|
||||
type serviceMessage struct {
|
||||
Type string `json:"_svctype"`
|
||||
Domain string `json:"_domain"`
|
||||
Service json.RawMessage `json:"Service"`
|
||||
}
|
||||
|
||||
type caaPolicyPayload struct {
|
||||
Records []caaRecordPayload `json:"caa"`
|
||||
}
|
||||
|
||||
// caaRecordPayload matches miekg/dns.CAA's JSON tags
|
||||
// (Hdr/Flag/Tag/Value) closely enough to round-trip through the
|
||||
// service body. We only keep Flag/Tag/Value; the Hdr is ignored.
|
||||
type caaRecordPayload struct {
|
||||
Flag uint8 `json:"Flag"`
|
||||
Tag string `json:"Tag"`
|
||||
Value string `json:"Value"`
|
||||
}
|
||||
|
||||
// Collect reads the auto-filled service body, validates the type, and
|
||||
// returns the CAA records flattened into CAAData. No network call.
|
||||
func (p *caaProvider) Collect(ctx context.Context, opts sdk.CheckerOptions) (any, error) {
|
||||
svc, err := serviceFromOptions(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if svc.Type != serviceType {
|
||||
return nil, fmt.Errorf("service is %q, expected %q", svc.Type, serviceType)
|
||||
}
|
||||
|
||||
var pol caaPolicyPayload
|
||||
if err := json.Unmarshal(svc.Service, &pol); err != nil {
|
||||
return nil, fmt.Errorf("decode CAA policy: %w", err)
|
||||
}
|
||||
|
||||
records := make([]CAARecord, 0, len(pol.Records))
|
||||
for _, r := range pol.Records {
|
||||
records = append(records, CAARecord{Flag: r.Flag, Tag: r.Tag, Value: r.Value})
|
||||
}
|
||||
|
||||
domain := svc.Domain
|
||||
if domain == "" {
|
||||
if v, _ := sdk.GetOption[string](opts, "domain"); v != "" {
|
||||
domain = v
|
||||
}
|
||||
}
|
||||
|
||||
return &CAAData{
|
||||
Domain: domain,
|
||||
Records: records,
|
||||
RunAt: time.Now().UTC().Format(time.RFC3339),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// serviceFromOptions normalizes the "service" option via a JSON
|
||||
// round-trip so the in-process plugin path (native Go value) and the
|
||||
// HTTP path (decoded map[string]any) both work without importing the
|
||||
// upstream type.
|
||||
func serviceFromOptions(opts sdk.CheckerOptions) (*serviceMessage, error) {
|
||||
v, ok := opts["service"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("service option missing")
|
||||
}
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal service option: %w", err)
|
||||
}
|
||||
var svc serviceMessage
|
||||
if err := json.Unmarshal(raw, &svc); err != nil {
|
||||
return nil, fmt.Errorf("decode service option: %w", err)
|
||||
}
|
||||
return &svc, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue