Bump Lego Version for GoDaddy DNS Provider

This commit is contained in:
Sami Jawhar 2017-11-30 01:44:03 -08:00 committed by Traefiker
parent 7081f3df58
commit e042ef3f27
7 changed files with 184 additions and 16 deletions

5
glide.lock generated
View file

@ -1,4 +1,4 @@
hash: 4595cac0a682ce8e36b78630f12a3cfab75307fc58cb4a1f5e416017d3ae20d6 hash: 8c5908b11f5078edd9ed93e2710ebb3a29b7e02d1259fddd679f8c46540becc9
updated: 2017-11-29T12:05:49.613148632+01:00 updated: 2017-11-29T12:05:49.613148632+01:00
imports: imports:
- name: cloud.google.com/go - name: cloud.google.com/go
@ -544,7 +544,7 @@ imports:
- plugin/rewrite - plugin/rewrite
- router - router
- name: github.com/xenolf/lego - name: github.com/xenolf/lego
version: 67c86d860a797ce2483f50d9174d4ed24984bef2 version: b929aa5aab5ad2e197bb3d74ef99fac61bfa47bc
subpackages: subpackages:
- acme - acme
- providers/dns - providers/dns
@ -558,6 +558,7 @@ imports:
- providers/dns/dyn - providers/dns/dyn
- providers/dns/exoscale - providers/dns/exoscale
- providers/dns/gandi - providers/dns/gandi
- providers/dns/godaddy
- providers/dns/googlecloud - providers/dns/googlecloud
- providers/dns/linode - providers/dns/linode
- providers/dns/namecheap - providers/dns/namecheap

View file

@ -65,7 +65,7 @@ import:
- package: github.com/vulcand/predicate - package: github.com/vulcand/predicate
version: 19b9dde14240d94c804ae5736ad0e1de10bf8fe6 version: 19b9dde14240d94c804ae5736ad0e1de10bf8fe6
- package: github.com/xenolf/lego - package: github.com/xenolf/lego
version: 67c86d860a797ce2483f50d9174d4ed24984bef2 version: b929aa5aab5ad2e197bb3d74ef99fac61bfa47bc
subpackages: subpackages:
- acme - acme
- package: gopkg.in/fsnotify.v1 - package: gopkg.in/fsnotify.v1

View file

@ -11,7 +11,6 @@ import (
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
"golang.org/x/net/publicsuffix"
) )
type preCheckDNSFunc func(fqdn, value string) (bool, error) type preCheckDNSFunc func(fqdn, value string) (bool, error)
@ -242,10 +241,6 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
labelIndexes := dns.Split(fqdn) labelIndexes := dns.Split(fqdn)
for _, index := range labelIndexes { for _, index := range labelIndexes {
domain := fqdn[index:] domain := fqdn[index:]
// Give up if we have reached the TLD
if isTLD(domain) {
break
}
in, err := dnsQuery(domain, dns.TypeSOA, nameservers, true) in, err := dnsQuery(domain, dns.TypeSOA, nameservers, true)
if err != nil { if err != nil {
@ -260,6 +255,13 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
// Check if we got a SOA RR in the answer section // Check if we got a SOA RR in the answer section
if in.Rcode == dns.RcodeSuccess { if in.Rcode == dns.RcodeSuccess {
// CNAME records cannot/should not exist at the root of a zone.
// So we skip a domain when a CNAME is found.
if dnsMsgContainsCNAME(in) {
continue
}
for _, ans := range in.Answer { for _, ans := range in.Answer {
if soa, ok := ans.(*dns.SOA); ok { if soa, ok := ans.(*dns.SOA); ok {
zone := soa.Hdr.Name zone := soa.Hdr.Name
@ -273,10 +275,12 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
return "", fmt.Errorf("Could not find the start of authority") return "", fmt.Errorf("Could not find the start of authority")
} }
func isTLD(domain string) bool { // dnsMsgContainsCNAME checks for a CNAME answer in msg
publicsuffix, _ := publicsuffix.PublicSuffix(UnFqdn(domain)) func dnsMsgContainsCNAME(msg *dns.Msg) bool {
if publicsuffix == UnFqdn(domain) { for _, ans := range msg.Answer {
return true if _, ok := ans.(*dns.CNAME); ok {
return true
}
} }
return false return false
} }

View file

@ -329,8 +329,10 @@ func run(c *cli.Context) error {
} }
func revoke(c *cli.Context) error { func revoke(c *cli.Context) error {
conf, acc, client := setup(c)
conf, _, client := setup(c) if acc.Registration == nil {
logger().Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", acc.Email)
}
err := checkFolder(conf.CertPath()) err := checkFolder(conf.CertPath())
if err != nil { if err != nil {
@ -355,7 +357,10 @@ func revoke(c *cli.Context) error {
} }
func renew(c *cli.Context) error { func renew(c *cli.Context) error {
conf, _, client := setup(c) conf, acc, client := setup(c)
if acc.Registration == nil {
logger().Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", acc.Email)
}
if len(c.GlobalStringSlice("domains")) <= 0 { if len(c.GlobalStringSlice("domains")) <= 0 {
logger().Fatal("Please specify at least one domain.") logger().Fatal("Please specify at least one domain.")

View file

@ -30,7 +30,7 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for azure. // NewDNSProvider returns a DNSProvider instance configured for azure.
// Credentials must be passed in the environment variables: AZURE_CLIENT_ID, // Credentials must be passed in the environment variables: AZURE_CLIENT_ID,
// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID // AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_RESOURCE_GROUP
func NewDNSProvider() (*DNSProvider, error) { func NewDNSProvider() (*DNSProvider, error) {
clientId := os.Getenv("AZURE_CLIENT_ID") clientId := os.Getenv("AZURE_CLIENT_ID")
clientSecret := os.Getenv("AZURE_CLIENT_SECRET") clientSecret := os.Getenv("AZURE_CLIENT_SECRET")

View file

@ -15,6 +15,7 @@ import (
"github.com/xenolf/lego/providers/dns/dyn" "github.com/xenolf/lego/providers/dns/dyn"
"github.com/xenolf/lego/providers/dns/exoscale" "github.com/xenolf/lego/providers/dns/exoscale"
"github.com/xenolf/lego/providers/dns/gandi" "github.com/xenolf/lego/providers/dns/gandi"
"github.com/xenolf/lego/providers/dns/godaddy"
"github.com/xenolf/lego/providers/dns/googlecloud" "github.com/xenolf/lego/providers/dns/googlecloud"
"github.com/xenolf/lego/providers/dns/linode" "github.com/xenolf/lego/providers/dns/linode"
"github.com/xenolf/lego/providers/dns/namecheap" "github.com/xenolf/lego/providers/dns/namecheap"
@ -54,6 +55,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
provider, err = gandi.NewDNSProvider() provider, err = gandi.NewDNSProvider()
case "gcloud": case "gcloud":
provider, err = googlecloud.NewDNSProvider() provider, err = googlecloud.NewDNSProvider()
case "godaddy":
provider, err = godaddy.NewDNSProvider()
case "linode": case "linode":
provider, err = linode.NewDNSProvider() provider, err = linode.NewDNSProvider()
case "manual": case "manual":

View file

@ -0,0 +1,155 @@
// Package godaddy implements a DNS provider for solving the DNS-01 challenge using godaddy DNS.
package godaddy
import (
"fmt"
"io"
"net/http"
"os"
"time"
"bytes"
"encoding/json"
"github.com/xenolf/lego/acme"
"io/ioutil"
"strings"
)
// GoDaddyAPIURL represents the API endpoint to call.
const apiURL = "https://api.godaddy.com"
// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
apiKey string
apiSecret string
}
// NewDNSProvider returns a DNSProvider instance configured for godaddy.
// Credentials must be passed in the environment variables: GODADDY_API_KEY
// and GODADDY_API_SECRET.
func NewDNSProvider() (*DNSProvider, error) {
apikey := os.Getenv("GODADDY_API_KEY")
secret := os.Getenv("GODADDY_API_SECRET")
return NewDNSProviderCredentials(apikey, secret)
}
// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for godaddy.
func NewDNSProviderCredentials(apiKey, apiSecret string) (*DNSProvider, error) {
if apiKey == "" || apiSecret == "" {
return nil, fmt.Errorf("GoDaddy credentials missing")
}
return &DNSProvider{apiKey, apiSecret}, nil
}
// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
return 120 * time.Second, 2 * time.Second
}
func (c *DNSProvider) extractRecordName(fqdn, domain string) string {
name := acme.UnFqdn(fqdn)
if idx := strings.Index(name, "."+domain); idx != -1 {
return name[:idx]
}
return name
}
// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
domainZone, err := c.getZone(fqdn)
if err != nil {
return err
}
if ttl < 600 {
ttl = 600
}
recordName := c.extractRecordName(fqdn, domainZone)
rec := []DNSRecord{
{
Type: "TXT",
Name: recordName,
Data: value,
Ttl: ttl,
},
}
return c.updateRecords(rec, domainZone, recordName)
}
func (c *DNSProvider) updateRecords(records []DNSRecord, domainZone string, recordName string) error {
body, err := json.Marshal(records)
if err != nil {
return err
}
var resp *http.Response
resp, err = c.makeRequest("PUT", fmt.Sprintf("/v1/domains/%s/records/TXT/%s", domainZone, recordName), bytes.NewReader(body))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
return fmt.Errorf("Could not create record %v; Status: %v; Body: %s\n", string(body), resp.StatusCode, string(bodyBytes))
}
return nil
}
// CleanUp sets null value in the TXT DNS record as GoDaddy has no proper DELETE record method
func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
domainZone, err := c.getZone(fqdn)
if err != nil {
return err
}
recordName := c.extractRecordName(fqdn, domainZone)
rec := []DNSRecord{
{
Type: "TXT",
Name: recordName,
Data: "null",
},
}
return c.updateRecords(rec, domainZone, recordName)
}
func (c *DNSProvider) getZone(fqdn string) (string, error) {
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
if err != nil {
return "", err
}
return acme.UnFqdn(authZone), nil
}
func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", apiURL, uri), body)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("sso-key %s:%s", c.apiKey, c.apiSecret))
client := http.Client{Timeout: 30 * time.Second}
return client.Do(req)
}
type DNSRecord struct {
Type string `json:"type"`
Name string `json:"name"`
Data string `json:"data"`
Priority int `json:"priority,omitempty"`
Ttl int `json:"ttl,omitempty"`
}