Skip to content

Commit

Permalink
fix(config): print wildcard domains with prefix *. (#198)
Browse files Browse the repository at this point in the history
* fix(config): print wildcard domains with prefix `*.`

* docs(api): update the comments about domains

* style(api): add back the suffix ASCII
  • Loading branch information
favonia authored Aug 11, 2022
1 parent 95df1ac commit caf370c
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 9 deletions.
9 changes: 9 additions & 0 deletions internal/api/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,29 @@ import (
"github.com/favonia/cloudflare-ddns/internal/pp"
)

// A DomainSplitter enumerates all possible zones from a domain.
type DomainSplitter interface {
// IsValid checks whether the current splitting point is still valid
IsValid() bool
// ZoneNameASCII gives the suffix (the zone), when it is still valid
ZoneNameASCII() string
// Next moves to the next possible splitting point, which might end up being invalid
Next()
}

// A Domain represents a domain name to update.
type Domain interface {
// DNSNameASCII gives a name suitable for accessing the Cloudflare API
DNSNameASCII() string
// Describe gives the most human-readable domain name that is still unambiguous
Describe() string
// Split gives a DomainSplitter that can be used to find zones
Split() DomainSplitter
}

//go:generate mockgen -destination=../mocks/mock_api.go -package=mocks . Handle

// Handle represents a generic API to update DNS records. Currently, the only implementation is Cloudflare.
type Handle interface {
ListRecords(ctx context.Context, ppfmt pp.PP, domain Domain, ipNet ipnet.Type) (map[string]netip.Addr, bool)
DeleteRecord(ctx context.Context, ppfmt pp.PP, domain Domain, ipNet ipnet.Type, id string) bool
Expand Down
6 changes: 6 additions & 0 deletions internal/api/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ func NewDomain(domain string) (Domain, error) {
}
}

// MustNewDomain normalizes the domain and ignores all errors.
func MustNewDomain(domain string) Domain {
d, _ := NewDomain(domain)
return d
}

func SortDomains(s []Domain) {
sort.Slice(s, func(i, j int) bool { return s[i].DNSNameASCII() < s[j].DNSNameASCII() })
}
5 changes: 5 additions & 0 deletions internal/api/domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ func TestNewDomain(t *testing.T) {
require.EqualError(t, err, tc.errString)
}
})
t.Run(tc.input, func(t *testing.T) {
t.Parallel()
normalized := api.MustNewDomain(tc.input)
require.Equal(t, tc.expected, normalized)
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/api/fqdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package api

import "strings"

// FQDN is a fully qualified domain in its ASCII or Unicode (when unambiguous) form.
// FQDN is a fully qualified domain in its ASCII form.
type FQDN string

func (f FQDN) DNSNameASCII() string { return string(f) }
Expand Down
4 changes: 2 additions & 2 deletions internal/api/wildcard.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package api

import "strings"

// Wildcard is a fully qualified zone name in its ASCII or Unicode (when unambiguous) form,
// represnting the wildcard domain name under the zone.
// Wildcard is a fully qualified zone name in its ASCII form, represnting the wildcard domain name
// under the zone. For example, Wildcard("example.org") represents "*.example.org".
type Wildcard string

func (w Wildcard) DNSNameASCII() string {
Expand Down
12 changes: 10 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ func ReadProviderMap(ppfmt pp.PP, field *map[ipnet.Type]provider.Provider) bool
return true
}

func describeDomains(domains []api.Domain) []string {
descriptions := make([]string, 0, len(domains))
for _, domain := range domains {
descriptions = append(descriptions, domain.Describe())
}
return descriptions
}

func (c *Config) Print(ppfmt pp.PP) {
if !ppfmt.IsEnabledFor(pp.Info) {
return
Expand All @@ -176,11 +184,11 @@ func (c *Config) Print(ppfmt pp.PP) {
ppfmt.Infof(pp.EmojiConfig, "Policies:")
inner.Infof(pp.EmojiBullet, "IPv4 provider: %s", provider.Name(c.Provider[ipnet.IP4]))
if c.Provider[ipnet.IP4] != nil {
inner.Infof(pp.EmojiBullet, "IPv4 domains: %v", c.Domains[ipnet.IP4])
inner.Infof(pp.EmojiBullet, "IPv4 domains: %v", describeDomains(c.Domains[ipnet.IP4]))
}
inner.Infof(pp.EmojiBullet, "IPv6 provider: %s", provider.Name(c.Provider[ipnet.IP6]))
if c.Provider[ipnet.IP6] != nil {
inner.Infof(pp.EmojiBullet, "IPv6 domains: %v", c.Domains[ipnet.IP6])
inner.Infof(pp.EmojiBullet, "IPv6 domains: %v", describeDomains(c.Domains[ipnet.IP6]))
}

ppfmt.Infof(pp.EmojiConfig, "Scheduling:")
Expand Down
49 changes: 45 additions & 4 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,9 @@ func TestPrintDefault(t *testing.T) {
mockPP.EXPECT().IncIndent().Return(innerMockPP),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Policies:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 domains: %v", []api.Domain(nil)),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 domains: %v", []string{}),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 domains: %v", []api.Domain(nil)),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 domains: %v", []string{}),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Timezone: %s", Some("UTC (UTC+00 now)", "Local (UTC+00 now)")),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Update frequency: %v", cron.MustNew("@every 5m")),
Expand All @@ -372,6 +372,47 @@ func TestPrintDefault(t *testing.T) {
config.Default().Print(mockPP)
}

//nolint:paralleltest // changing the environment variable TZ
func TestPrintDomains(t *testing.T) {
mockCtrl := gomock.NewController(t)

store(t, "TZ", "UTC")

mockPP := mocks.NewMockPP(mockCtrl)
innerMockPP := mocks.NewMockPP(mockCtrl)
gomock.InOrder(
mockPP.EXPECT().IsEnabledFor(pp.Info).Return(true),
mockPP.EXPECT().Infof(pp.EmojiEnvVars, "Current settings:"),
mockPP.EXPECT().IncIndent().Return(mockPP),
mockPP.EXPECT().IncIndent().Return(innerMockPP),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Policies:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 domains: %v", []string{"test4.org", "*.test4.org"}),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 domains: %v", []string{"test6.org", "*.test6.org"}),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Timezone: %s", Some("UTC (UTC+00 now)", "Local (UTC+00 now)")),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Update frequency: %v", cron.MustNew("@every 5m")),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Update on start? %t", true),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Delete on stop? %t", false),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Cache expiration: %v", time.Hour*6),
mockPP.EXPECT().Infof(pp.EmojiConfig, "New DNS records:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "TTL: %s", "1 (automatic)"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Proxied: %t", false),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Timeouts:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IP detection: %v", time.Second*5),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Record updating: %v", time.Second*30),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Monitors: (none)"),
)

c := config.Default()

c.Domains[ipnet.IP4] = []api.Domain{api.MustNewDomain("test4.org"), api.MustNewDomain("*.test4.org")}
c.Domains[ipnet.IP6] = []api.Domain{api.MustNewDomain("test6.org"), api.MustNewDomain("*.test6.org")}

c.Print(mockPP)
}

//nolint:paralleltest // changing the environment variable TZ
func TestPrintEmpty(t *testing.T) {
mockCtrl := gomock.NewController(t)
Expand Down Expand Up @@ -423,9 +464,9 @@ func TestPrintMonitors(t *testing.T) {
mockPP.EXPECT().IncIndent().Return(innerMockPP),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Policies:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 domains: %v", []api.Domain(nil)),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv4 domains: %v", []string{}),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 provider: %s", "cloudflare.trace"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 domains: %v", []api.Domain(nil)),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "IPv6 domains: %v", []string{}),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Timezone: %s", Some("UTC (UTC+00 now)", "Local (UTC+00 now)")),
innerMockPP.EXPECT().Infof(pp.EmojiBullet, "Update frequency: %v", cron.MustNew("@every 5m")),
Expand Down

0 comments on commit caf370c

Please sign in to comment.