diff --git a/.golangci.toml b/.golangci.toml
index b6aed20b..0e4a8e73 100644
--- a/.golangci.toml
+++ b/.golangci.toml
@@ -90,7 +90,7 @@
text = "`envTest` is a global variable"
[[issues.exclude-rules]]
path = "providers/dns/namecheap/namecheap_test.go"
- text = "`(tldsMock|testCases)` is a global variable"
+ text = "`testCases` is a global variable"
[[issues.exclude-rules]]
path = "providers/dns/acmedns/acmedns_test.go"
text = "`(errorClientErr|errorStorageErr|egTestAccount)` is a global variable"
diff --git a/providers/dns/namecheap/client.go b/providers/dns/namecheap/client.go
index 85bec85f..1936f2c9 100644
--- a/providers/dns/namecheap/client.go
+++ b/providers/dns/namecheap/client.go
@@ -42,39 +42,6 @@ type getHostsResponse struct {
Hosts []Record `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
}
-type getTldsResponse struct {
- XMLName xml.Name `xml:"ApiResponse"`
- Errors []apiError `xml:"Errors>Error"`
- Result []struct {
- Name string `xml:",attr"`
- } `xml:"CommandResponse>Tlds>Tld"`
-}
-
-// getTLDs requests the list of available TLDs.
-// https://www.namecheap.com/support/api/methods/domains/get-tld-list.aspx
-func (d *DNSProvider) getTLDs() (map[string]string, error) {
- request, err := d.newRequestGet("namecheap.domains.getTldList")
- if err != nil {
- return nil, err
- }
-
- var gtr getTldsResponse
- err = d.do(request, >r)
- if err != nil {
- return nil, err
- }
-
- if len(gtr.Errors) > 0 {
- return nil, fmt.Errorf("%s [%d]", gtr.Errors[0].Description, gtr.Errors[0].Number)
- }
-
- tlds := make(map[string]string)
- for _, t := range gtr.Result {
- tlds[t.Name] = t.Name
- }
- return tlds, nil
-}
-
// getHosts reads the full list of DNS host records.
// https://www.namecheap.com/support/api/methods/domains-dns/get-hosts.aspx
func (d *DNSProvider) getHosts(sld, tld string) ([]Record, error) {
diff --git a/providers/dns/namecheap/namecheap.go b/providers/dns/namecheap/namecheap.go
index 3a5a4ad6..fd48e19a 100644
--- a/providers/dns/namecheap/namecheap.go
+++ b/providers/dns/namecheap/namecheap.go
@@ -13,6 +13,7 @@ import (
"github.com/go-acme/lego/v3/challenge/dns01"
"github.com/go-acme/lego/v3/log"
"github.com/go-acme/lego/v3/platform/config/env"
+ "golang.org/x/net/publicsuffix"
)
// Notes about namecheap's tool API:
@@ -129,12 +130,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present installs a TXT record for the DNS challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- tlds, err := d.getTLDs()
- if err != nil {
- return fmt.Errorf("namecheap: %v", err)
- }
-
- ch, err := newChallenge(domain, keyAuth, tlds)
+ ch, err := newChallenge(domain, keyAuth)
if err != nil {
return fmt.Errorf("namecheap: %v", err)
}
@@ -169,12 +165,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes a TXT record used for a previous DNS challenge.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- tlds, err := d.getTLDs()
- if err != nil {
- return fmt.Errorf("namecheap: %v", err)
- }
-
- ch, err := newChallenge(domain, keyAuth, tlds)
+ ch, err := newChallenge(domain, keyAuth)
if err != nil {
return fmt.Errorf("namecheap: %v", err)
}
@@ -226,25 +217,17 @@ func getClientIP(client *http.Client, debug bool) (addr string, err error) {
return string(clientIP), nil
}
-// newChallenge builds a challenge record from a domain name, a challenge
-// authentication key, and a map of available TLDs.
-func newChallenge(domain, keyAuth string, tlds map[string]string) (*challenge, error) {
+// newChallenge builds a challenge record from a domain name and a challenge authentication key.
+func newChallenge(domain, keyAuth string) (*challenge, error) {
domain = dns01.UnFqdn(domain)
- parts := strings.Split(domain, ".")
- // Find the longest matching TLD.
- longest := -1
- for i := len(parts); i > 0; i-- {
- t := strings.Join(parts[i-1:], ".")
- if _, found := tlds[t]; found {
- longest = i - 1
- }
- }
- if longest < 1 {
+ tld, _ := publicsuffix.PublicSuffix(domain)
+ if tld == domain {
return nil, fmt.Errorf("invalid domain name %q", domain)
}
- tld := strings.Join(parts[longest:], ".")
+ parts := strings.Split(domain, ".")
+ longest := len(parts) - strings.Count(tld, ".") - 1
sld := parts[longest-1]
var host string
diff --git a/providers/dns/namecheap/namecheap_test.go b/providers/dns/namecheap/namecheap_test.go
index 67a49d89..015195d9 100644
--- a/providers/dns/namecheap/namecheap_test.go
+++ b/providers/dns/namecheap/namecheap_test.go
@@ -18,16 +18,6 @@ const (
envTestClientIP = "10.0.0.1"
)
-var tldsMock = map[string]string{
- "com.au": "com.au",
- "com": "com",
- "co.uk": "co.uk",
- "uk": "uk",
- "edu": "edu",
- "co.com": "co.com",
- "za.com": "za.com",
-}
-
func TestDNSProvider_getHosts(t *testing.T) {
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
@@ -36,7 +26,7 @@ func TestDNSProvider_getHosts(t *testing.T) {
provider := mockDNSProvider(mock.URL)
- ch, err := newChallenge(test.domain, "", tldsMock)
+ ch, err := newChallenge(test.domain, "")
require.NoError(t, err)
hosts, err := provider.getHosts(ch.sld, ch.tld)
@@ -77,7 +67,7 @@ func TestDNSProvider_setHosts(t *testing.T) {
prov := mockDNSProvider(mock.URL)
- ch, err := newChallenge(test.domain, "", tldsMock)
+ ch, err := newChallenge(test.domain, "")
require.NoError(t, err)
hosts, err := prov.getHosts(ch.sld, ch.tld)
@@ -144,23 +134,22 @@ func TestDomainSplit(t *testing.T) {
{domain: "test.co.com", valid: true, tld: "co.com", sld: "test"},
{domain: "www.test.com.au", valid: true, tld: "com.au", sld: "test", host: "www"},
{domain: "www.za.com", valid: true, tld: "za.com", sld: "www"},
+ {domain: "my.test.tf", valid: true, tld: "tf", sld: "test", host: "my"},
{},
{domain: "a"},
{domain: "com"},
+ {domain: "com.au"},
{domain: "co.com"},
{domain: "co.uk"},
- {domain: "test.au"},
+ {domain: "tf"},
{domain: "za.com"},
- {domain: "www.za"},
- {domain: "www.test.au"},
- {domain: "www.test.unk"},
}
for _, test := range tests {
test := test
t.Run(test.domain, func(t *testing.T) {
valid := true
- ch, err := newChallenge(test.domain, "", tldsMock)
+ ch, err := newChallenge(test.domain, "")
if err != nil {
valid = false
}
@@ -172,30 +161,26 @@ func TestDomainSplit(t *testing.T) {
}
if test.valid && valid {
- assertEq(t, "domain", ch.domain, test.domain)
- assertEq(t, "tld", ch.tld, test.tld)
- assertEq(t, "sld", ch.sld, test.sld)
- assertEq(t, "host", ch.host, test.host)
+ require.NotNil(t, ch)
+ assert.Equal(t, test.domain, ch.domain, "domain")
+ assert.Equal(t, test.tld, ch.tld, "tld")
+ assert.Equal(t, test.sld, ch.sld, "sld")
+ assert.Equal(t, test.host, ch.host, "host")
}
})
}
}
-func assertEq(t *testing.T, variable, got, want string) {
- if got != want {
- t.Errorf("Expected %s to be '%s' but got '%s'", variable, want, got)
- }
-}
-
func assertHdr(tc *testCase, t *testing.T, values *url.Values) {
- ch, _ := newChallenge(tc.domain, "", tldsMock)
+ t.Helper()
- assertEq(t, "ApiUser", values.Get("ApiUser"), envTestUser)
- assertEq(t, "ApiKey", values.Get("ApiKey"), envTestKey)
- assertEq(t, "UserName", values.Get("UserName"), envTestUser)
- assertEq(t, "ClientIp", values.Get("ClientIp"), envTestClientIP)
- assertEq(t, "SLD", values.Get("SLD"), ch.sld)
- assertEq(t, "TLD", values.Get("TLD"), ch.tld)
+ ch, _ := newChallenge(tc.domain, "")
+ assert.Equal(t, envTestUser, values.Get("ApiUser"), "ApiUser")
+ assert.Equal(t, envTestKey, values.Get("ApiKey"), "ApiKey")
+ assert.Equal(t, envTestUser, values.Get("UserName"), "UserName")
+ assert.Equal(t, envTestClientIP, values.Get("ClientIp"), "ClientIp")
+ assert.Equal(t, ch.sld, values.Get("SLD"), "SLD")
+ assert.Equal(t, ch.tld, values.Get("TLD"), "TLD")
}
func mockServer(tc *testCase, t *testing.T) http.Handler {
@@ -209,9 +194,6 @@ func mockServer(tc *testCase, t *testing.T) http.Handler {
assertHdr(tc, t, &values)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, tc.getHostsResponse)
- case "namecheap.domains.getTldList":
- w.WriteHeader(http.StatusOK)
- fmt.Fprint(w, responseGetTlds)
default:
t.Errorf("Unexpected GET command: %s", cmd)
}
@@ -373,18 +355,3 @@ const responseGetHostsErrorBadAPIKey1 = `
--5:00
0
`
-
-const responseGetTlds = `
-
-
-
- namecheap.domains.getTldList
-
-
- Most recognized top level domain
-
-
- PHX01SBAPI01
- --5:00
- 0.004
-`