From de70a1b5931ca4ffb7fb79c5db4931dc70bf5ed6 Mon Sep 17 00:00:00 2001 From: Haylin Moore Date: Thu, 10 Jul 2025 19:53:37 -0700 Subject: [PATCH] feat: add support for libdns ZoneLister --- provider.go | 37 +++++++++++++++++++++++++++++++++++++ provider_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/provider.go b/provider.go index 973daa9..27109c7 100644 --- a/provider.go +++ b/provider.go @@ -292,6 +292,23 @@ func (p *Provider) DeleteRecords(ctx context.Context, zone string, records []lib return ret, nil } +// ListZones lists all the zones on an account. +func (p *Provider) ListZones(ctx context.Context) ([]libdns.Zone, error) { + // https://desec.readthedocs.io/en/latest/dns/domains.html#listing-domains + desecZones, err := p.listZones(ctx) + if err != nil { + return nil, err + } + + zones := make([]libdns.Zone, len(desecZones)) + for i, zone := range desecZones { + zones[i] = libdns.Zone{ + Name: zone.Name, + } + } + return zones, nil +} + // https://desec.readthedocs.io/en/latest/dns/rrsets.html#rrset-field-reference type rrSet struct { Subname string `json:"subname"` @@ -538,6 +555,25 @@ func (p *Provider) listRRSets(ctx context.Context, zone string) ([]rrSet, error) return out, nil } +// https://desec.readthedocs.io/en/latest/dns/domains.html#domain-field-reference +type domain struct { + Name string `json:"name"` +} + +func (p *Provider) listZones(ctx context.Context) ([]domain, error) { + // https://desec.readthedocs.io/en/latest/dns/domains.html#listing-domains + buf, err := p.httpDo(ctx, "GET", "https://desec.io/api/v1/domains/", nil) + if err != nil { + return nil, err + } + + var out []domain + if err := json.Unmarshal(buf, &out); err != nil { + return nil, fmt.Errorf("decoding json: %v", err) + } + return out, nil +} + func (p *Provider) putRRSets(ctx context.Context, zone string, rrs []rrSet) error { if len(rrs) == 0 { return nil @@ -567,4 +603,5 @@ var ( _ libdns.RecordAppender = (*Provider)(nil) _ libdns.RecordSetter = (*Provider)(nil) _ libdns.RecordDeleter = (*Provider)(nil) + _ libdns.ZoneLister = (*Provider)(nil) ) diff --git a/provider_test.go b/provider_test.go index 822afda..222aa1d 100644 --- a/provider_test.go +++ b/provider_test.go @@ -693,3 +693,51 @@ func TestDeleteRecords(t *testing.T) { t.Fatalf("p.GetRecords() unexpected diff [-want +got]: %s", diff) } } + +func TestListZones(t *testing.T) { + if *token == "" || *domain == "" { + t.Skip("skipping integration test; both -token and -domain must be set") + } + + ctx := context.Background() + if deadline, ok := t.Deadline(); ok { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, deadline) + t.Cleanup(cancel) + } + + p := &desec.Provider{ + Token: *token, + } + + testDomains := []string{ + *domain, + "test1-" + *domain, + "test2-" + *domain, + } + + for _, testDomain := range testDomains { + if domainExists(ctx, t, testDomain) { + t.Fatalf("domain %q exists, but it should not", testDomain) + } + createDomain(ctx, t, testDomain) + domain := testDomain + t.Cleanup(func() { deleteDomain(ctx, t, domain) }) + } + + zones, err := p.ListZones(ctx) + if err != nil { + t.Fatal(err) + } + + zoneMap := make(map[string]bool) + for _, zone := range zones { + zoneMap[zone.Name] = true + } + + for _, testDomain := range testDomains { + if !zoneMap[testDomain] { + t.Errorf("Failed to find %s in ListZones call", testDomain) + } + } +}