From 64afecac214f73c26bf6f39f4c0d59adfcc67fd8 Mon Sep 17 00:00:00 2001 From: Amir Omidi Date: Thu, 9 Mar 2023 16:22:00 -0500 Subject: [PATCH] Add Google Domains as DNS provider (#1839) Co-authored-by: Ludovic Fernandez --- README.md | 36 ++--- cmd/zz_gen_cmd_dnshelp.go | 20 +++ docs/content/dns/zz_gen_googledomains.md | 67 +++++++++ docs/data/zz_cli_help.toml | 2 +- providers/dns/dns_providers.go | 3 + providers/dns/googledomains/googledomains.go | 139 ++++++++++++++++++ .../dns/googledomains/googledomains.toml | 22 +++ .../dns/googledomains/googledomains_test.go | 111 ++++++++++++++ 8 files changed, 381 insertions(+), 19 deletions(-) create mode 100644 docs/content/dns/zz_gen_googledomains.md create mode 100644 providers/dns/googledomains/googledomains.go create mode 100644 providers/dns/googledomains/googledomains.toml create mode 100644 providers/dns/googledomains/googledomains_test.go diff --git a/README.md b/README.md index a967f9e9..dd8ae198 100644 --- a/README.md +++ b/README.md @@ -60,24 +60,24 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns). | [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Epik](https://go-acme.github.io/lego/dns/epik/) | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | | [External program](https://go-acme.github.io/lego/dns/exec/) | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/) | [G-Core Labs](https://go-acme.github.io/lego/dns/gcore/) | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | | [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | -| [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | -| [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) | [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | -| [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | -| [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | -| [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | -| [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | -| [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | -| [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | -| [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [Nodion](https://go-acme.github.io/lego/dns/nodion/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) | -| [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | [plesk.com](https://go-acme.github.io/lego/dns/plesk/) | -| [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) | -| [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | -| [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) | -| [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | -| [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Vercel](https://go-acme.github.io/lego/dns/vercel/) | -| [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | -| [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Websupport](https://go-acme.github.io/lego/dns/websupport/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | -| [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | +| [Google Domains](https://go-acme.github.io/lego/dns/googledomains/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | +| [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) | [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | +| [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | +| [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | +| [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) | +| [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) | +| [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | +| [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | +| [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [Nodion](https://go-acme.github.io/lego/dns/nodion/) | +| [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | +| [plesk.com](https://go-acme.github.io/lego/dns/plesk/) | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | +| [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | +| [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) | +| [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | +| [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | +| [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | +| [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Websupport](https://go-acme.github.io/lego/dns/websupport/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | +| [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index d3a7d401..edaff3e0 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -57,6 +57,7 @@ func allDNSCodes() string { "gcore", "glesys", "godaddy", + "googledomains", "hetzner", "hostingde", "hosttech", @@ -1042,6 +1043,25 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/godaddy`) + case "googledomains": + // generated from: providers/dns/googledomains/googledomains.toml + ew.writeln(`Configuration for Google Domains.`) + ew.writeln(`Code: 'googledomains'`) + ew.writeln(`Since: 'v4.11.0'`) + ew.writeln() + + ew.writeln(`Credentials:`) + ew.writeln(` - "GOOGLE_DOMAINS_ACCESS_TOKEN": Access token`) + ew.writeln() + + ew.writeln(`Additional Configuration:`) + ew.writeln(` - "GOOGLE_DOMAINS_HTTP_TIMEOUT": API request timeout`) + ew.writeln(` - "GOOGLE_DOMAINS_POLLING_INTERVAL": Time between DNS propagation check`) + ew.writeln(` - "GOOGLE_DOMAINS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`) + + ew.writeln() + ew.writeln(`More information: https://go-acme.github.io/lego/dns/googledomains`) + case "hetzner": // generated from: providers/dns/hetzner/hetzner.toml ew.writeln(`Configuration for Hetzner.`) diff --git a/docs/content/dns/zz_gen_googledomains.md b/docs/content/dns/zz_gen_googledomains.md new file mode 100644 index 00000000..01a859fc --- /dev/null +++ b/docs/content/dns/zz_gen_googledomains.md @@ -0,0 +1,67 @@ +--- +title: "Google Domains" +date: 2019-03-03T16:39:46+01:00 +draft: false +slug: googledomains +dnsprovider: + since: "v4.11.0" + code: "googledomains" + url: "https://domains.google" +--- + + + + + + +Configuration for [Google Domains](https://domains.google). + + + + +- Code: `googledomains` +- Since: v4.11.0 + + +Here is an example bash command using the Google Domains provider: + +```bash +GOOGLE_DOMAINS_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ +lego --email you@example.com --dns gdomains --domains my.example.org run +``` + + + + +## Credentials + +| Environment Variable Name | Description | +|-----------------------|-------------| +| `GOOGLE_DOMAINS_ACCESS_TOKEN` | Access token | + +The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. +More information [here]({{< ref "dns#configuration-and-credentials" >}}). + + +## Additional Configuration + +| Environment Variable Name | Description | +|--------------------------------|-------------| +| `GOOGLE_DOMAINS_HTTP_TIMEOUT` | API request timeout | +| `GOOGLE_DOMAINS_POLLING_INTERVAL` | Time between DNS propagation check | +| `GOOGLE_DOMAINS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation | + +The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. +More information [here]({{< ref "dns#configuration-and-credentials" >}}). + + + + +## More information + + +- [Go client](https://github.com/googleapis/google-api-go-client) + + + + diff --git a/docs/data/zz_cli_help.toml b/docs/data/zz_cli_help.toml index 70deb542..cf08d7e0 100644 --- a/docs/data/zz_cli_help.toml +++ b/docs/data/zz_cli_help.toml @@ -125,7 +125,7 @@ To display the documentation for a specific DNS provider, run: $ lego dnshelp -c code Supported DNS providers: - acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandexcloud, zoneee, zonomi + acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandexcloud, zoneee, zonomi More information: https://go-acme.github.io/lego/dns """ diff --git a/providers/dns/dns_providers.go b/providers/dns/dns_providers.go index 6a30138e..d27da5d3 100644 --- a/providers/dns/dns_providers.go +++ b/providers/dns/dns_providers.go @@ -48,6 +48,7 @@ import ( "github.com/go-acme/lego/v4/providers/dns/gcore" "github.com/go-acme/lego/v4/providers/dns/glesys" "github.com/go-acme/lego/v4/providers/dns/godaddy" + "github.com/go-acme/lego/v4/providers/dns/googledomains" "github.com/go-acme/lego/v4/providers/dns/hetzner" "github.com/go-acme/lego/v4/providers/dns/hostingde" "github.com/go-acme/lego/v4/providers/dns/hosttech" @@ -210,6 +211,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) { return glesys.NewDNSProvider() case "godaddy": return godaddy.NewDNSProvider() + case "googledomains": + return googledomains.NewDNSProvider() case "hetzner": return hetzner.NewDNSProvider() case "hostingde": diff --git a/providers/dns/googledomains/googledomains.go b/providers/dns/googledomains/googledomains.go new file mode 100644 index 00000000..254fd655 --- /dev/null +++ b/providers/dns/googledomains/googledomains.go @@ -0,0 +1,139 @@ +// Package googledomains implements a DNS provider for solving the DNS-01 challenge using Google Domains DNS API. +package googledomains + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/go-acme/lego/v4/platform/config/env" + "google.golang.org/api/acmedns/v1" + "google.golang.org/api/option" +) + +// Environment variables names. +const ( + envNamespace = "GOOGLE_DOMAINS_" + + EnvAccessToken = envNamespace + "ACCESS_TOKEN" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" + EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT" +) + +// static compile-time check on interface implementation. +var _ challenge.Provider = &DNSProvider{} + +// Config is used to configure the creation of the DNSProvider. +type Config struct { + AccessToken string + PollingInterval time.Duration + PropagationTimeout time.Duration + HTTPClient *http.Client +} + +// NewDefaultConfig returns a default configuration for the DNSProvider. +func NewDefaultConfig() *Config { + return &Config{ + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), + PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second), + HTTPClient: &http.Client{ + Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), + }, + } +} + +// NewDNSProvider returns the Google Domains DNS provider with a default configuration. +func NewDNSProvider() (*DNSProvider, error) { + values, err := env.Get(EnvAccessToken) + if err != nil { + return nil, fmt.Errorf("googledomains: %w", err) + } + + config := NewDefaultConfig() + config.AccessToken = values[EnvAccessToken] + + return NewDNSProviderConfig(config) +} + +// NewDNSProviderConfig returns the Google Domains DNS provider with the provided config. +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, fmt.Errorf("googledomains: the configuration of the DNS provider is nil") + } + + if config.AccessToken == "" { + return nil, fmt.Errorf("googledomains: access token is missing") + } + + service, err := acmedns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient)) + if err != nil { + return nil, fmt.Errorf("googledomains: error creating acme dns service: %w", err) + } + + return &DNSProvider{ + config: config, + acmedns: service, + }, nil +} + +type DNSProvider struct { + config *Config + acmedns *acmedns.Service +} + +func (d *DNSProvider) Present(domain, token, keyAuth string) error { + zone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain)) + if err != nil { + return fmt.Errorf("googledomains: error finding zone for domain %s: %w", domain, err) + } + + rotateReq := acmedns.RotateChallengesRequest{ + AccessToken: d.config.AccessToken, + RecordsToAdd: []*acmedns.AcmeTxtRecord{getAcmeTxtRecord(domain, keyAuth)}, + KeepExpiredRecords: false, + } + + call := d.acmedns.AcmeChallengeSets.RotateChallenges(zone, &rotateReq) + _, err = call.Do() + if err != nil { + return fmt.Errorf("googledomains: error adding challenge for domain %s: %w", domain, err) + } + return nil +} + +func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { + zone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain)) + if err != nil { + return fmt.Errorf("googledomains: error finding zone for domain %s: %w", domain, err) + } + + rotateReq := acmedns.RotateChallengesRequest{ + AccessToken: d.config.AccessToken, + RecordsToRemove: []*acmedns.AcmeTxtRecord{getAcmeTxtRecord(domain, keyAuth)}, + KeepExpiredRecords: false, + } + + call := d.acmedns.AcmeChallengeSets.RotateChallenges(zone, &rotateReq) + _, err = call.Do() + if err != nil { + return fmt.Errorf("googledomains: error cleaning up challenge for domain %s: %w", domain, err) + } + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func getAcmeTxtRecord(domain, keyAuth string) *acmedns.AcmeTxtRecord { + challengeInfo := dns01.GetChallengeInfo(domain, keyAuth) + + return &acmedns.AcmeTxtRecord{ + Fqdn: challengeInfo.EffectiveFQDN, + Digest: challengeInfo.Value, + } +} diff --git a/providers/dns/googledomains/googledomains.toml b/providers/dns/googledomains/googledomains.toml new file mode 100644 index 00000000..d31073d8 --- /dev/null +++ b/providers/dns/googledomains/googledomains.toml @@ -0,0 +1,22 @@ +Name = "Google Domains" +Description = '''''' +URL = "https://domains.google" +Code = "googledomains" +Since = "v4.11.0" + +Example = ''' +GOOGLE_DOMAINS_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ +lego --email you@example.com --dns gdomains --domains my.example.org run +''' + +[Configuration] + [Configuration.Credentials] + GOOGLE_DOMAINS_ACCESS_TOKEN = "Access token" + [Configuration.Additional] + GOOGLE_DOMAINS_POLLING_INTERVAL = "Time between DNS propagation check" + GOOGLE_DOMAINS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation" + GOOGLE_DOMAINS_HTTP_TIMEOUT = "API request timeout" + +[Links] + GoClient = "https://github.com/googleapis/google-api-go-client" + diff --git a/providers/dns/googledomains/googledomains_test.go b/providers/dns/googledomains/googledomains_test.go new file mode 100644 index 00000000..038fb534 --- /dev/null +++ b/providers/dns/googledomains/googledomains_test.go @@ -0,0 +1,111 @@ +package googledomains + +import ( + "testing" + + "github.com/go-acme/lego/v4/platform/tester" + "github.com/stretchr/testify/require" +) + +const envDomain = envNamespace + "DOMAIN" + +var envTest = tester.NewEnvTest(EnvAccessToken). + WithDomain(envDomain). + WithLiveTestRequirements(EnvAccessToken, envDomain) + +func TestNewDNSProvider(t *testing.T) { + testCases := []struct { + desc string + envVars map[string]string + expected string + }{ + { + desc: "success", + envVars: map[string]string{ + EnvAccessToken: "abc", + }, + expected: "", + }, + { + desc: "missing credentials", + envVars: map[string]string{}, + expected: "googledomains: some credentials information are missing: GOOGLE_DOMAINS_ACCESS_TOKEN", + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + defer envTest.RestoreEnv() + envTest.ClearEnv() + envTest.Apply(test.envVars) + p, err := NewDNSProvider() + if test.expected == "" { + require.NoError(t, err) + require.NotNil(t, p) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), test.expected) + } + }) + } +} + +func TestNewDNSProviderConfig(t *testing.T) { + testCases := []struct { + desc string + accessToken string + expected string + }{ + { + desc: "success", + accessToken: "abc", + }, + { + desc: "missing credentials", + expected: "googledomains: access token is missing", + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + config := NewDefaultConfig() + config.AccessToken = test.accessToken + + p, err := NewDNSProviderConfig(config) + + if test.expected == "" { + require.NoError(t, err) + require.NotNil(t, p) + require.NotNil(t, p.config) + } else { + require.EqualError(t, err, test.expected) + } + }) + } +} + +func TestLivePresent(t *testing.T) { + if !envTest.IsLiveTest() { + t.Skip("skipping live test") + } + + envTest.RestoreEnv() + provider, err := NewDNSProvider() + require.NoError(t, err) + + err = provider.Present(envTest.GetDomain(), "", "123d==") + require.NoError(t, err) +} + +func TestLiveCleanUp(t *testing.T) { + if !envTest.IsLiveTest() { + t.Skip("skipping live test") + } + + envTest.RestoreEnv() + provider, err := NewDNSProvider() + require.NoError(t, err) + + err = provider.CleanUp(envTest.GetDomain(), "", "123d==") + require.NoError(t, err) +}