From bc1c3842ee5d6959a8276fff4e2a6954b2df2c67 Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Sun, 31 Mar 2024 12:45:54 -0400 Subject: [PATCH] Update dependencies and go version --- README.md | 2 +- go.mod | 6 +- go.sum | 9 +- main.go | 4 +- vendor/github.com/libdns/cloudflare/client.go | 6 +- vendor/github.com/libdns/cloudflare/models.go | 60 +++++++--- .../github.com/libdns/cloudflare/provider.go | 11 +- vendor/github.com/libdns/libdns/README.md | 18 +-- vendor/github.com/libdns/libdns/libdns.go | 106 +++++++++++++++++- vendor/modules.txt | 8 +- 10 files changed, 186 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 3420586..d49b730 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Usage of cloudflare-dns-cli: IP address (default 127.0.0.1) -m Set mx record with cname value -o string - Path to save all records as json, e.g. ./records.json + Path to save all records as json, e.g. ./records.json, '-' for stdout -s string Subdomain, e.g. blog. Use @ for root (default "") -x Delete records of subdomain diff --git a/go.mod b/go.mod index 6f5dd1a..7aade53 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module go.balki.me/cloudflare-dns-cli -go 1.21 +go 1.22.1 require ( - github.com/libdns/cloudflare v0.1.0 - github.com/libdns/libdns v0.2.1 + github.com/libdns/cloudflare v0.1.1 + github.com/libdns/libdns v0.2.2 ) diff --git a/go.sum b/go.sum index 5e2ef10..2d40e60 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ -github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic= -github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8= -github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= -github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= -github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= +github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054= +github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= diff --git a/main.go b/main.go index 4d37107..0c6eed0 100644 --- a/main.go +++ b/main.go @@ -63,9 +63,9 @@ func genRecord() (libdns.Record, error) { func selectRecordsToDelete(recs []libdns.Record) []libdns.Record { name := func() string { if sub == "@" { - return domain + return "" } - return fmt.Sprintf("%s.%s", sub, domain) + return sub }() recs = func() (result []libdns.Record) { for _, r := range recs { diff --git a/vendor/github.com/libdns/cloudflare/client.go b/vendor/github.com/libdns/cloudflare/client.go index 78a4389..dd73e30 100644 --- a/vendor/github.com/libdns/cloudflare/client.go +++ b/vendor/github.com/libdns/cloudflare/client.go @@ -12,7 +12,11 @@ import ( ) func (p *Provider) createRecord(ctx context.Context, zoneInfo cfZone, record libdns.Record) (cfDNSRecord, error) { - jsonBytes, err := json.Marshal(cloudflareRecord(record)) + cfRec, err := cloudflareRecord(record) + if err != nil { + return cfDNSRecord{}, err + } + jsonBytes, err := json.Marshal(cfRec) if err != nil { return cfDNSRecord{}, err } diff --git a/vendor/github.com/libdns/cloudflare/models.go b/vendor/github.com/libdns/cloudflare/models.go index 8fb1a96..aed78a5 100644 --- a/vendor/github.com/libdns/cloudflare/models.go +++ b/vendor/github.com/libdns/cloudflare/models.go @@ -2,6 +2,7 @@ package cloudflare import ( "encoding/json" + "strings" "time" "github.com/libdns/libdns" @@ -61,7 +62,7 @@ type cfDNSRecord struct { ZoneName string `json:"zone_name,omitempty"` CreatedOn time.Time `json:"created_on,omitempty"` ModifiedOn time.Time `json:"modified_on,omitempty"` - Data *struct { + Data struct { // LOC LatDegrees int `json:"lat_degrees,omitempty"` LatMinutes int `json:"lat_minutes,omitempty"` @@ -80,9 +81,9 @@ type cfDNSRecord struct { Service string `json:"service,omitempty"` Proto string `json:"proto,omitempty"` Name string `json:"name,omitempty"` - Priority int `json:"priority,omitempty"` - Weight int `json:"weight,omitempty"` - Port int `json:"port,omitempty"` + Priority uint `json:"priority,omitempty"` + Weight uint `json:"weight,omitempty"` + Port uint `json:"port,omitempty"` Target string `json:"target,omitempty"` // DNSKEY @@ -109,6 +110,18 @@ type cfDNSRecord struct { } func (r cfDNSRecord) libdnsRecord(zone string) libdns.Record { + if r.Type == "SRV" { + srv := libdns.SRV{ + Service: strings.TrimPrefix(r.Data.Service, "_"), + Proto: strings.TrimPrefix(r.Data.Proto, "_"), + Name: r.Data.Name, + Priority: r.Data.Priority, + Weight: r.Data.Weight, + Port: r.Data.Port, + Target: r.Data.Target, + } + return srv.ToRecord() + } return libdns.Record{ Type: r.Type, Name: libdns.RelativeName(r.Name, zone), @@ -118,14 +131,29 @@ func (r cfDNSRecord) libdnsRecord(zone string) libdns.Record { } } -func cloudflareRecord(r libdns.Record) cfDNSRecord { - return cfDNSRecord{ - ID: r.ID, - Type: r.Type, - Name: r.Name, - Content: r.Value, - TTL: int(r.TTL.Seconds()), +func cloudflareRecord(r libdns.Record) (cfDNSRecord, error) { + rec := cfDNSRecord{ + ID: r.ID, + Type: r.Type, + TTL: int(r.TTL.Seconds()), } + if r.Type == "SRV" { + srv, err := r.ToSRV() + if err != nil { + return cfDNSRecord{}, err + } + rec.Data.Service = "_" + srv.Service + rec.Data.Priority = srv.Priority + rec.Data.Weight = srv.Weight + rec.Data.Proto = "_" + srv.Proto + rec.Data.Name = srv.Name + rec.Data.Port = srv.Port + rec.Data.Target = srv.Target + } else { + rec.Name = r.Name + rec.Content = r.Value + } + return rec, nil } // All API responses have this structure. @@ -133,10 +161,14 @@ type cfResponse struct { Result json.RawMessage `json:"result,omitempty"` Success bool `json:"success"` Errors []struct { - Code int `json:"code"` - Message string `json:"message"` + Code int `json:"code"` + Message string `json:"message"` + ErrorChain []struct { + Code int `json:"code"` + Message string `json:"message"` + } `json:"error_chain,omitempty"` } `json:"errors,omitempty"` - Messages []interface{} `json:"messages,omitempty"` + Messages []any `json:"messages,omitempty"` ResultInfo *cfResultInfo `json:"result_info,omitempty"` } diff --git a/vendor/github.com/libdns/cloudflare/provider.go b/vendor/github.com/libdns/cloudflare/provider.go index 0149a61..413cd31 100644 --- a/vendor/github.com/libdns/cloudflare/provider.go +++ b/vendor/github.com/libdns/cloudflare/provider.go @@ -131,7 +131,10 @@ func (p *Provider) SetRecords(ctx context.Context, zone string, records []libdns var results []libdns.Record for _, rec := range records { - oldRec := cloudflareRecord(rec) + oldRec, err := cloudflareRecord(rec) + if err != nil { + return nil, err + } oldRec.ZoneID = zoneInfo.ID if rec.ID == "" { // the record might already exist, even if we don't know the ID yet @@ -155,7 +158,11 @@ func (p *Provider) SetRecords(ctx context.Context, zone string, records []libdns oldRec.ID = matches[0].ID } // record exists; update it - result, err := p.updateRecord(ctx, oldRec, cloudflareRecord(rec)) + cfRec, err := cloudflareRecord(rec) + if err != nil { + return nil, err + } + result, err := p.updateRecord(ctx, oldRec, cfRec) if err != nil { return nil, err } diff --git a/vendor/github.com/libdns/libdns/README.md b/vendor/github.com/libdns/libdns/README.md index 661a072..b5f77b4 100644 --- a/vendor/github.com/libdns/libdns/README.md +++ b/vendor/github.com/libdns/libdns/README.md @@ -41,14 +41,18 @@ recs, err := provider.GetRecords(ctx, zone) // create records (AppendRecords is similar) newRecs, err := provider.SetRecords(ctx, zone, []libdns.Record{ - Type: "A", - Name: "sub", - Value: "1.2.3.4", + { + Type: "A", + Name: "sub", + Value: "1.2.3.4", + }, }) // delete records (this example uses provider-assigned ID) deletedRecs, err := provider.DeleteRecords(ctx, zone, []libdns.Record{ - ID: "foobar", + { + ID: "foobar", + }, }) // no matter which provider you use, the code stays the same! @@ -56,11 +60,11 @@ deletedRecs, err := provider.DeleteRecords(ctx, zone, []libdns.Record{ ``` -## Implementing new providers +## Implementing new provider packages -Providers are 100% written and maintained by the community! We all maintain just the packages for providers we use. +Provider packages are 100% written and maintained by the community! Collectively, we all maintain the packages for providers we individually use. -**[Instructions for adding new providers](https://github.com/libdns/libdns/wiki/Implementing-providers)** are on this repo's wiki. Please feel free to contribute. +**[Instructions for adding new libdns packages](https://github.com/libdns/libdns/wiki/Implementing-a-libdns-package)** are on this repo's wiki. Please feel free to contribute yours! ## Similar projects diff --git a/vendor/github.com/libdns/libdns/libdns.go b/vendor/github.com/libdns/libdns/libdns.go index 9a2bbcb..867575f 100644 --- a/vendor/github.com/libdns/libdns/libdns.go +++ b/vendor/github.com/libdns/libdns/libdns.go @@ -10,15 +10,18 @@ // that input records conform to this standard, while also ensuring that // output records do; adjustments to record names may need to be made before // or after provider API calls, for example, to maintain consistency with -// all other libdns provider implementations. Helper functions are available -// in this package to convert between relative and absolute names. +// all other libdns packages. Helper functions are available in this package +// to convert between relative and absolute names. // // Although zone names are a required input, libdns does not coerce any // particular representation of DNS zones; only records. Since zone name and // records are separate inputs in libdns interfaces, it is up to the caller // to pair a zone's name with its records in a way that works for them. // -// All interface implementations must be safe for concurrent/parallel use. +// All interface implementations must be safe for concurrent/parallel use, +// meaning 1) no data races, and 2) simultaneous method calls must result +// in either both their expected outcomes or an error. +// // For example, if AppendRecords() is called at the same time and two API // requests are made to the provider at the same time, the result of both // requests must be visible after they both complete; if the provider does @@ -32,6 +35,8 @@ package libdns import ( "context" + "fmt" + "strconv" "strings" "time" ) @@ -89,7 +94,23 @@ type RecordDeleter interface { DeleteRecords(ctx context.Context, zone string, recs []Record) ([]Record, error) } +// ZoneLister can list available DNS zones. +type ZoneLister interface { + // ListZones returns the list of available DNS zones for use by + // other libdns methods. + // + // Implementations must honor context cancellation and be safe for + // concurrent use. + ListZones(ctx context.Context) ([]Zone, error) +} + // Record is a generalized representation of a DNS record. +// +// The values of this struct should be free of zone-file-specific syntax, +// except if this struct's fields do not sufficiently represent all the +// fields of a certain record type; in that case, the remaining data for +// which there are not specific fields should be stored in the Value as +// it appears in the zone file. type Record struct { // provider-specific metadata ID string @@ -101,7 +122,76 @@ type Record struct { TTL time.Duration // type-dependent record fields - Priority int // used by MX, SRV, and URI records + Priority uint // HTTPS, MX, SRV, and URI records + Weight uint // SRV and URI records +} + +// Zone is a generalized representation of a DNS zone. +type Zone struct { + Name string +} + +// ToSRV parses the record into a SRV struct with fully-parsed, literal values. +// +// EXPERIMENTAL; subject to change or removal. +func (r Record) ToSRV() (SRV, error) { + if r.Type != "SRV" { + return SRV{}, fmt.Errorf("record type not SRV: %s", r.Type) + } + + fields := strings.Fields(r.Value) + if len(fields) != 2 { + return SRV{}, fmt.Errorf("malformed SRV value; expected: ' '") + } + + port, err := strconv.Atoi(fields[0]) + if err != nil { + return SRV{}, fmt.Errorf("invalid port %s: %v", fields[0], err) + } + if port < 0 { + return SRV{}, fmt.Errorf("port cannot be < 0: %d", port) + } + + parts := strings.SplitN(r.Name, ".", 3) + if len(parts) < 3 { + return SRV{}, fmt.Errorf("name %v does not contain enough fields; expected format: '_service._proto.name'", r.Name) + } + + return SRV{ + Service: strings.TrimPrefix(parts[0], "_"), + Proto: strings.TrimPrefix(parts[1], "_"), + Name: parts[2], + Priority: r.Priority, + Weight: r.Weight, + Port: uint(port), + Target: fields[1], + }, nil +} + +// SRV contains all the parsed data of an SRV record. +// +// EXPERIMENTAL; subject to change or removal. +type SRV struct { + Service string // no leading "_" + Proto string // no leading "_" + Name string + Priority uint + Weight uint + Port uint + Target string +} + +// ToRecord converts the parsed SRV data to a Record struct. +// +// EXPERIMENTAL; subject to change or removal. +func (s SRV) ToRecord() Record { + return Record{ + Type: "SRV", + Name: fmt.Sprintf("_%s._%s.%s", s.Service, s.Proto, s.Name), + Priority: s.Priority, + Weight: s.Weight, + Value: fmt.Sprintf("%d %s", s.Port, s.Target), + } } // RelativeName makes fqdn relative to zone. For example, for a FQDN of @@ -109,7 +199,13 @@ type Record struct { // // If fqdn cannot be expressed relative to zone, the input fqdn is returned. func RelativeName(fqdn, zone string) string { - return strings.TrimSuffix(strings.TrimSuffix(fqdn, zone), ".") + // liberally ignore trailing dots on both fqdn and zone, because + // the relative name won't have a trailing dot anyway; I assume + // this won't be problematic...? + // (initially implemented because Cloudflare returns "fully- + // qualified" domains in their records without a trailing dot, + // but the input zone typically has a trailing dot) + return strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(fqdn, "."), strings.TrimSuffix(zone, ".")), ".") } // AbsoluteName makes name into a fully-qualified domain name (FQDN) by diff --git a/vendor/modules.txt b/vendor/modules.txt index ffbfb98..677a569 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,6 @@ -# github.com/libdns/cloudflare v0.1.0 -## explicit; go 1.14 +# github.com/libdns/cloudflare v0.1.1 +## explicit; go 1.18 github.com/libdns/cloudflare -# github.com/libdns/libdns v0.2.1 -## explicit; go 1.14 +# github.com/libdns/libdns v0.2.2 +## explicit; go 1.18 github.com/libdns/libdns