Rename provider types as provider names are already in the package name. Added package level comments and fixed the name of the interface the providers are importing.

This commit is contained in:
xenolf 2016-03-11 03:46:09 +01:00
parent 9008ec6949
commit 2ae35a755d
12 changed files with 99 additions and 93 deletions

View file

@ -234,8 +234,8 @@ func FindZoneByFqdn(fqdn, nameserver string) (string, error) {
return "", fmt.Errorf("NS %s did not return the expected SOA record in the authority section", nameserver) return "", fmt.Errorf("NS %s did not return the expected SOA record in the authority section", nameserver)
} }
// clearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing. // ClearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing.
func clearFqdnCache() { func ClearFqdnCache() {
fqdnToZone = map[string]string{} fqdnToZone = map[string]string{}
} }

View file

@ -72,23 +72,23 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
var provider acme.ChallengeProvider var provider acme.ChallengeProvider
switch c.GlobalString("dns") { switch c.GlobalString("dns") {
case "cloudflare": case "cloudflare":
provider, err = cloudflare.NewDNSProviderCloudFlare("", "") provider, err = cloudflare.NewDNSProvider("", "")
case "digitalocean": case "digitalocean":
authToken := os.Getenv("DO_AUTH_TOKEN") authToken := os.Getenv("DO_AUTH_TOKEN")
provider, err = digitalocean.NewDNSProviderDigitalOcean(authToken) provider, err = digitalocean.NewDNSProvider(authToken)
case "dnsimple": case "dnsimple":
provider, err = dnsimple.NewDNSProviderDNSimple("", "") provider, err = dnsimple.NewDNSProvider("", "")
case "route53": case "route53":
awsRegion := os.Getenv("AWS_REGION") awsRegion := os.Getenv("AWS_REGION")
provider, err = route53.NewDNSProviderRoute53("", "", awsRegion) provider, err = route53.NewDNSProvider("", "", awsRegion)
case "rfc2136": case "rfc2136":
nameserver := os.Getenv("RFC2136_NAMESERVER") nameserver := os.Getenv("RFC2136_NAMESERVER")
tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM") tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM")
tsigKey := os.Getenv("RFC2136_TSIG_KEY") tsigKey := os.Getenv("RFC2136_TSIG_KEY")
tsigSecret := os.Getenv("RFC2136_TSIG_SECRET") tsigSecret := os.Getenv("RFC2136_TSIG_SECRET")
provider, err = rfc2136.NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret) provider, err = rfc2136.NewDNSProvider(nameserver, tsigAlgorithm, tsigKey, tsigSecret)
case "manual": case "manual":
provider, err = acme.NewDNSProviderManual() provider, err = acme.NewDNSProviderManual()
} }

View file

@ -1,3 +1,4 @@
// Package cloudflare implements a DNS provider for solving the DNS-01 challenge using cloudflare DNS.
package cloudflare package cloudflare
import ( import (
@ -17,15 +18,15 @@ import (
// TODO: Unexport? // TODO: Unexport?
const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4" const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4"
// DNSProviderCloudFlare is an implementation of the DNSProvider interface // DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProviderCloudFlare struct { type DNSProvider struct {
authEmail string authEmail string
authKey string authKey string
} }
// NewDNSProviderCloudFlare returns a DNSProviderCloudFlare instance with a configured cloudflare client. // NewDNSProvider returns a DNSProvider instance with a configured cloudflare client.
// Credentials can either be passed as arguments or through CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY env vars. // Credentials can either be passed as arguments or through CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY env vars.
func NewDNSProviderCloudFlare(cloudflareEmail, cloudflareKey string) (*DNSProviderCloudFlare, error) { func NewDNSProvider(cloudflareEmail, cloudflareKey string) (*DNSProvider, error) {
if cloudflareEmail == "" || cloudflareKey == "" { if cloudflareEmail == "" || cloudflareKey == "" {
cloudflareEmail, cloudflareKey = cloudflareEnvAuth() cloudflareEmail, cloudflareKey = cloudflareEnvAuth()
if cloudflareEmail == "" || cloudflareKey == "" { if cloudflareEmail == "" || cloudflareKey == "" {
@ -33,14 +34,14 @@ func NewDNSProviderCloudFlare(cloudflareEmail, cloudflareKey string) (*DNSProvid
} }
} }
return &DNSProviderCloudFlare{ return &DNSProvider{
authEmail: cloudflareEmail, authEmail: cloudflareEmail,
authKey: cloudflareKey, authKey: cloudflareKey,
}, nil }, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error { func (c *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
zoneID, err := c.getHostedZoneID(fqdn) zoneID, err := c.getHostedZoneID(fqdn)
if err != nil { if err != nil {
@ -68,7 +69,7 @@ func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error {
} }
// CleanUp removes the TXT record matching the specified parameters // CleanUp removes the TXT record matching the specified parameters
func (c *DNSProviderCloudFlare) CleanUp(domain, token, keyAuth string) error { func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, _, _ := acme.DNS01Record(domain, keyAuth) fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
record, err := c.findTxtRecord(fqdn) record, err := c.findTxtRecord(fqdn)
@ -84,7 +85,7 @@ func (c *DNSProviderCloudFlare) CleanUp(domain, token, keyAuth string) error {
return nil return nil
} }
func (c *DNSProviderCloudFlare) getHostedZoneID(fqdn string) (string, error) { func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
// HostedZone represents a CloudFlare DNS zone // HostedZone represents a CloudFlare DNS zone
type HostedZone struct { type HostedZone struct {
ID string `json:"id"` ID string `json:"id"`
@ -118,7 +119,7 @@ func (c *DNSProviderCloudFlare) getHostedZoneID(fqdn string) (string, error) {
return hostedZone.ID, nil return hostedZone.ID, nil
} }
func (c *DNSProviderCloudFlare) findTxtRecord(fqdn string) (*cloudFlareRecord, error) { func (c *DNSProvider) findTxtRecord(fqdn string) (*cloudFlareRecord, error) {
zoneID, err := c.getHostedZoneID(fqdn) zoneID, err := c.getHostedZoneID(fqdn)
if err != nil { if err != nil {
return nil, err return nil, err
@ -144,7 +145,7 @@ func (c *DNSProviderCloudFlare) findTxtRecord(fqdn string) (*cloudFlareRecord, e
return nil, fmt.Errorf("No existing record found for %s", fqdn) return nil, fmt.Errorf("No existing record found for %s", fqdn)
} }
func (c *DNSProviderCloudFlare) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) { func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
// APIError contains error details for failed requests // APIError contains error details for failed requests
type APIError struct { type APIError struct {
Code int `json:"code,omitempty"` Code int `json:"code,omitempty"`

View file

@ -29,26 +29,26 @@ func restoreCloudFlareEnv() {
os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey) os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey)
} }
func TestNewDNSProviderCloudFlareValid(t *testing.T) { func TestNewDNSProviderValid(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "") os.Setenv("CLOUDFLARE_EMAIL", "")
os.Setenv("CLOUDFLARE_API_KEY", "") os.Setenv("CLOUDFLARE_API_KEY", "")
_, err := NewDNSProviderCloudFlare("123", "123") _, err := NewDNSProvider("123", "123")
assert.NoError(t, err) assert.NoError(t, err)
restoreCloudFlareEnv() restoreCloudFlareEnv()
} }
func TestNewDNSProviderCloudFlareValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "test@example.com") os.Setenv("CLOUDFLARE_EMAIL", "test@example.com")
os.Setenv("CLOUDFLARE_API_KEY", "123") os.Setenv("CLOUDFLARE_API_KEY", "123")
_, err := NewDNSProviderCloudFlare("", "") _, err := NewDNSProvider("", "")
assert.NoError(t, err) assert.NoError(t, err)
restoreCloudFlareEnv() restoreCloudFlareEnv()
} }
func TestNewDNSProviderCloudFlareMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "") os.Setenv("CLOUDFLARE_EMAIL", "")
os.Setenv("CLOUDFLARE_API_KEY", "") os.Setenv("CLOUDFLARE_API_KEY", "")
_, err := NewDNSProviderCloudFlare("", "") _, err := NewDNSProvider("", "")
assert.EqualError(t, err, "CloudFlare credentials missing") assert.EqualError(t, err, "CloudFlare credentials missing")
restoreCloudFlareEnv() restoreCloudFlareEnv()
} }
@ -58,7 +58,7 @@ func TestCloudFlarePresent(t *testing.T) {
t.Skip("skipping live test") t.Skip("skipping live test")
} }
provider, err := NewDNSProviderCloudFlare(cflareEmail, cflareAPIKey) provider, err := NewDNSProvider(cflareEmail, cflareAPIKey)
assert.NoError(t, err) assert.NoError(t, err)
err = provider.Present(cflareDomain, "", "123d==") err = provider.Present(cflareDomain, "", "123d==")
@ -72,7 +72,7 @@ func TestCloudFlareCleanUp(t *testing.T) {
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
provider, err := NewDNSProviderCloudFlare(cflareEmail, cflareAPIKey) provider, err := NewDNSProvider(cflareEmail, cflareAPIKey)
assert.NoError(t, err) assert.NoError(t, err)
err = provider.CleanUp(cflareDomain, "", "123d==") err = provider.CleanUp(cflareDomain, "", "123d==")

View file

@ -1,3 +1,4 @@
// Package digitalocean implements a DNS provider for solving the DNS-01 challenge using digitalocean DNS.
package digitalocean package digitalocean
import ( import (
@ -10,26 +11,26 @@ import (
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
// DNSProviderDigitalOcean is an implementation of the DNSProvider interface // DNSProvider is an implementation of the acme.ChallengeProvider interface
// that uses DigitalOcean's REST API to manage TXT records for a domain. // that uses DigitalOcean's REST API to manage TXT records for a domain.
type DNSProviderDigitalOcean struct { type DNSProvider struct {
apiAuthToken string apiAuthToken string
recordIDs map[string]int recordIDs map[string]int
recordIDsMu sync.Mutex recordIDsMu sync.Mutex
} }
// NewDNSProviderDigitalOcean returns a new DNSProviderDigitalOcean instance. // NewDNSProvider returns a new DNSProvider instance.
// apiAuthToken is the personal access token created in the DigitalOcean account // apiAuthToken is the personal access token created in the DigitalOcean account
// control panel, and it will be sent in bearer authorization headers. // control panel, and it will be sent in bearer authorization headers.
func NewDNSProviderDigitalOcean(apiAuthToken string) (*DNSProviderDigitalOcean, error) { func NewDNSProvider(apiAuthToken string) (*DNSProvider, error) {
return &DNSProviderDigitalOcean{ return &DNSProvider{
apiAuthToken: apiAuthToken, apiAuthToken: apiAuthToken,
recordIDs: make(map[string]int), recordIDs: make(map[string]int),
}, nil }, nil
} }
// Present creates a TXT record using the specified parameters // Present creates a TXT record using the specified parameters
func (d *DNSProviderDigitalOcean) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// txtRecordRequest represents the request body to DO's API to make a TXT record // txtRecordRequest represents the request body to DO's API to make a TXT record
type txtRecordRequest struct { type txtRecordRequest struct {
RecordType string `json:"type"` RecordType string `json:"type"`
@ -89,7 +90,7 @@ func (d *DNSProviderDigitalOcean) Present(domain, token, keyAuth string) error {
} }
// CleanUp removes the TXT record matching the specified parameters // CleanUp removes the TXT record matching the specified parameters
func (d *DNSProviderDigitalOcean) CleanUp(domain, token, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, _, _ := acme.DNS01Record(domain, keyAuth) fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
// get the record's unique ID from when we created it // get the record's unique ID from when we created it

View file

@ -53,7 +53,7 @@ func TestDigitalOceanPresent(t *testing.T) {
defer mock.Close() defer mock.Close()
digitalOceanBaseURL = mock.URL digitalOceanBaseURL = mock.URL
doprov, err := NewDNSProviderDigitalOcean(fakeDigitalOceanAuth) doprov, err := NewDNSProvider(fakeDigitalOceanAuth)
if doprov == nil { if doprov == nil {
t.Fatal("Expected non-nil DigitalOcean provider, but was nil") t.Fatal("Expected non-nil DigitalOcean provider, but was nil")
} }
@ -95,7 +95,7 @@ func TestDigitalOceanCleanUp(t *testing.T) {
defer mock.Close() defer mock.Close()
digitalOceanBaseURL = mock.URL digitalOceanBaseURL = mock.URL
doprov, err := NewDNSProviderDigitalOcean(fakeDigitalOceanAuth) doprov, err := NewDNSProvider(fakeDigitalOceanAuth)
if doprov == nil { if doprov == nil {
t.Fatal("Expected non-nil DigitalOcean provider, but was nil") t.Fatal("Expected non-nil DigitalOcean provider, but was nil")
} }

View file

@ -1,3 +1,4 @@
// Package dnsimple implements a DNS provider for solving the DNS-01 challenge using dnsimple DNS.
package dnsimple package dnsimple
import ( import (
@ -9,15 +10,15 @@ import (
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
// DNSProviderDNSimple is an implementation of the DNSProvider interface. // DNSProvider is an implementation of the acme.ChallengeProvider interface.
type DNSProviderDNSimple struct { type DNSProvider struct {
client *dnsimple.Client client *dnsimple.Client
} }
// NewDNSProviderDNSimple returns a DNSProviderDNSimple instance with a configured dnsimple client. // NewDNSProvider returns a DNSProvider instance with a configured dnsimple client.
// Authentication is either done using the passed credentials or - when empty - using the environment // Authentication is either done using the passed credentials or - when empty - using the environment
// variables DNSIMPLE_EMAIL and DNSIMPLE_API_KEY. // variables DNSIMPLE_EMAIL and DNSIMPLE_API_KEY.
func NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProviderDNSimple, error) { func NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProvider, error) {
if dnsimpleEmail == "" || dnsimpleAPIKey == "" { if dnsimpleEmail == "" || dnsimpleAPIKey == "" {
dnsimpleEmail, dnsimpleAPIKey = dnsimpleEnvAuth() dnsimpleEmail, dnsimpleAPIKey = dnsimpleEnvAuth()
if dnsimpleEmail == "" || dnsimpleAPIKey == "" { if dnsimpleEmail == "" || dnsimpleAPIKey == "" {
@ -25,7 +26,7 @@ func NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProviderD
} }
} }
c := &DNSProviderDNSimple{ c := &DNSProvider{
client: dnsimple.NewClient(dnsimpleAPIKey, dnsimpleEmail), client: dnsimple.NewClient(dnsimpleAPIKey, dnsimpleEmail),
} }
@ -33,7 +34,7 @@ func NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProviderD
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfil the dns-01 challenge.
func (c *DNSProviderDNSimple) Present(domain, token, keyAuth string) error { func (c *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
zoneID, zoneName, err := c.getHostedZone(domain) zoneID, zoneName, err := c.getHostedZone(domain)
@ -51,7 +52,7 @@ func (c *DNSProviderDNSimple) Present(domain, token, keyAuth string) error {
} }
// CleanUp removes the TXT record matching the specified parameters. // CleanUp removes the TXT record matching the specified parameters.
func (c *DNSProviderDNSimple) CleanUp(domain, token, keyAuth string) error { func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, _, _ := acme.DNS01Record(domain, keyAuth) fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
records, err := c.findTxtRecords(domain, fqdn) records, err := c.findTxtRecords(domain, fqdn)
@ -68,7 +69,7 @@ func (c *DNSProviderDNSimple) CleanUp(domain, token, keyAuth string) error {
return nil return nil
} }
func (c *DNSProviderDNSimple) getHostedZone(domain string) (string, string, error) { func (c *DNSProvider) getHostedZone(domain string) (string, string, error) {
domains, _, err := c.client.Domains.List() domains, _, err := c.client.Domains.List()
if err != nil { if err != nil {
return "", "", fmt.Errorf("DNSimple API call failed: %v", err) return "", "", fmt.Errorf("DNSimple API call failed: %v", err)
@ -89,7 +90,7 @@ func (c *DNSProviderDNSimple) getHostedZone(domain string) (string, string, erro
return fmt.Sprintf("%v", hostedDomain.Id), hostedDomain.Name, nil return fmt.Sprintf("%v", hostedDomain.Id), hostedDomain.Name, nil
} }
func (c *DNSProviderDNSimple) findTxtRecords(domain, fqdn string) ([]dnsimple.Record, error) { func (c *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnsimple.Record, error) {
zoneID, zoneName, err := c.getHostedZone(domain) zoneID, zoneName, err := c.getHostedZone(domain)
if err != nil { if err != nil {
return nil, err return nil, err
@ -111,7 +112,7 @@ func (c *DNSProviderDNSimple) findTxtRecords(domain, fqdn string) ([]dnsimple.Re
return records, nil return records, nil
} }
func (c *DNSProviderDNSimple) newTxtRecord(zone, fqdn, value string, ttl int) *dnsimple.Record { func (c *DNSProvider) newTxtRecord(zone, fqdn, value string, ttl int) *dnsimple.Record {
name := c.extractRecordName(fqdn, zone) name := c.extractRecordName(fqdn, zone)
return &dnsimple.Record{ return &dnsimple.Record{
@ -122,7 +123,7 @@ func (c *DNSProviderDNSimple) newTxtRecord(zone, fqdn, value string, ttl int) *d
} }
} }
func (c *DNSProviderDNSimple) extractRecordName(fqdn, domain string) string { func (c *DNSProvider) extractRecordName(fqdn, domain string) string {
name := acme.UnFqdn(fqdn) name := acme.UnFqdn(fqdn)
if idx := strings.Index(name, "."+domain); idx != -1 { if idx := strings.Index(name, "."+domain); idx != -1 {
return name[:idx] return name[:idx]

View file

@ -29,25 +29,25 @@ func restoreDNSimpleEnv() {
os.Setenv("DNSIMPLE_API_KEY", dnsimpleAPIKey) os.Setenv("DNSIMPLE_API_KEY", dnsimpleAPIKey)
} }
func TestNewDNSProviderDNSimpleValid(t *testing.T) { func TestNewDNSProviderValid(t *testing.T) {
os.Setenv("DNSIMPLE_EMAIL", "") os.Setenv("DNSIMPLE_EMAIL", "")
os.Setenv("DNSIMPLE_API_KEY", "") os.Setenv("DNSIMPLE_API_KEY", "")
_, err := NewDNSProviderDNSimple("example@example.com", "123") _, err := NewDNSProvider("example@example.com", "123")
assert.NoError(t, err) assert.NoError(t, err)
restoreDNSimpleEnv() restoreDNSimpleEnv()
} }
func TestNewDNSProviderDNSimpleValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("DNSIMPLE_EMAIL", "example@example.com") os.Setenv("DNSIMPLE_EMAIL", "example@example.com")
os.Setenv("DNSIMPLE_API_KEY", "123") os.Setenv("DNSIMPLE_API_KEY", "123")
_, err := NewDNSProviderDNSimple("", "") _, err := NewDNSProvider("", "")
assert.NoError(t, err) assert.NoError(t, err)
restoreDNSimpleEnv() restoreDNSimpleEnv()
} }
func TestNewDNSProviderDNSimpleMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
os.Setenv("DNSIMPLE_EMAIL", "") os.Setenv("DNSIMPLE_EMAIL", "")
os.Setenv("DNSIMPLE_API_KEY", "") os.Setenv("DNSIMPLE_API_KEY", "")
_, err := NewDNSProviderDNSimple("", "") _, err := NewDNSProvider("", "")
assert.EqualError(t, err, "DNSimple credentials missing") assert.EqualError(t, err, "DNSimple credentials missing")
restoreDNSimpleEnv() restoreDNSimpleEnv()
} }
@ -57,7 +57,7 @@ func TestLiveDNSimplePresent(t *testing.T) {
t.Skip("skipping live test") t.Skip("skipping live test")
} }
provider, err := NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey) provider, err := NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey)
assert.NoError(t, err) assert.NoError(t, err)
err = provider.Present(dnsimpleDomain, "", "123d==") err = provider.Present(dnsimpleDomain, "", "123d==")
@ -71,7 +71,7 @@ func TestLiveDNSimpleCleanUp(t *testing.T) {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
provider, err := NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey) provider, err := NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey)
assert.NoError(t, err) assert.NoError(t, err)
err = provider.CleanUp(dnsimpleDomain, "", "123d==") err = provider.CleanUp(dnsimpleDomain, "", "123d==")

View file

@ -1,3 +1,4 @@
// Package rfc2136 implements a DNS provider for solving the DNS-01 challenge using the rfc2136 dynamic update.
package rfc2136 package rfc2136
import ( import (
@ -10,19 +11,19 @@ import (
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
// DNSProviderRFC2136 is an implementation of the ChallengeProvider interface that // DNSProvider is an implementation of the acme.ChallengeProvider interface that
// uses dynamic DNS updates (RFC 2136) to create TXT records on a nameserver. // uses dynamic DNS updates (RFC 2136) to create TXT records on a nameserver.
type DNSProviderRFC2136 struct { type DNSProvider struct {
nameserver string nameserver string
tsigAlgorithm string tsigAlgorithm string
tsigKey string tsigKey string
tsigSecret string tsigSecret string
} }
// NewDNSProviderRFC2136 returns a new DNSProviderRFC2136 instance. // NewDNSProvider returns a new DNSProvider instance.
// To disable TSIG authentication 'tsigAlgorithm, 'tsigKey' and 'tsigSecret' must be set to the empty string. // To disable TSIG authentication 'tsigAlgorithm, 'tsigKey' and 'tsigSecret' must be set to the empty string.
// 'nameserver' must be a network address in the the form "host" or "host:port". // 'nameserver' must be a network address in the the form "host" or "host:port".
func NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret string) (*DNSProviderRFC2136, error) { func NewDNSProvider(nameserver, tsigAlgorithm, tsigKey, tsigSecret string) (*DNSProvider, error) {
// Append the default DNS port if none is specified. // Append the default DNS port if none is specified.
if _, _, err := net.SplitHostPort(nameserver); err != nil { if _, _, err := net.SplitHostPort(nameserver); err != nil {
if strings.Contains(err.Error(), "missing port") { if strings.Contains(err.Error(), "missing port") {
@ -31,7 +32,7 @@ func NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret string
return nil, err return nil, err
} }
} }
d := &DNSProviderRFC2136{ d := &DNSProvider{
nameserver: nameserver, nameserver: nameserver,
} }
if tsigAlgorithm == "" { if tsigAlgorithm == "" {
@ -47,18 +48,18 @@ func NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret string
} }
// Present creates a TXT record using the specified parameters // Present creates a TXT record using the specified parameters
func (r *DNSProviderRFC2136) Present(domain, token, keyAuth string) error { func (r *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
return r.changeRecord("INSERT", fqdn, value, ttl) return r.changeRecord("INSERT", fqdn, value, ttl)
} }
// CleanUp removes the TXT record matching the specified parameters // CleanUp removes the TXT record matching the specified parameters
func (r *DNSProviderRFC2136) CleanUp(domain, token, keyAuth string) error { func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
return r.changeRecord("REMOVE", fqdn, value, ttl) return r.changeRecord("REMOVE", fqdn, value, ttl)
} }
func (r *DNSProviderRFC2136) changeRecord(action, fqdn, value string, ttl int) error { func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
// Find the zone for the given fqdn // Find the zone for the given fqdn
zone, err := acme.FindZoneByFqdn(fqdn, r.nameserver) zone, err := acme.FindZoneByFqdn(fqdn, r.nameserver)
if err != nil { if err != nil {

View file

@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/xenolf/lego/acme"
) )
var ( var (
@ -26,7 +27,7 @@ var (
var reqChan = make(chan *dns.Msg, 10) var reqChan = make(chan *dns.Msg, 10)
func TestRFC2136CanaryLocalTestServer(t *testing.T) { func TestRFC2136CanaryLocalTestServer(t *testing.T) {
clearFqdnCache() acme.ClearFqdnCache()
dns.HandleFunc("example.com.", serverHandlerHello) dns.HandleFunc("example.com.", serverHandlerHello)
defer dns.HandleRemove("example.com.") defer dns.HandleRemove("example.com.")
@ -50,7 +51,7 @@ func TestRFC2136CanaryLocalTestServer(t *testing.T) {
} }
func TestRFC2136ServerSuccess(t *testing.T) { func TestRFC2136ServerSuccess(t *testing.T) {
clearFqdnCache() acme.ClearFqdnCache()
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
@ -60,9 +61,9 @@ func TestRFC2136ServerSuccess(t *testing.T) {
} }
defer server.Shutdown() defer server.Shutdown()
provider, err := NewDNSProviderRFC2136(addrstr, "", "", "") provider, err := NewDNSProvider(addrstr, "", "", "")
if err != nil { if err != nil {
t.Fatalf("Expected NewDNSProviderRFC2136() to return no error but the error was -> %v", err) t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
} }
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil { if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil {
t.Errorf("Expected Present() to return no error but the error was -> %v", err) t.Errorf("Expected Present() to return no error but the error was -> %v", err)
@ -70,7 +71,7 @@ func TestRFC2136ServerSuccess(t *testing.T) {
} }
func TestRFC2136ServerError(t *testing.T) { func TestRFC2136ServerError(t *testing.T) {
clearFqdnCache() acme.ClearFqdnCache()
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
@ -80,9 +81,9 @@ func TestRFC2136ServerError(t *testing.T) {
} }
defer server.Shutdown() defer server.Shutdown()
provider, err := NewDNSProviderRFC2136(addrstr, "", "", "") provider, err := NewDNSProvider(addrstr, "", "", "")
if err != nil { if err != nil {
t.Fatalf("Expected NewDNSProviderRFC2136() to return no error but the error was -> %v", err) t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
} }
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err == nil { if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err == nil {
t.Errorf("Expected Present() to return an error but it did not.") t.Errorf("Expected Present() to return an error but it did not.")
@ -92,7 +93,7 @@ func TestRFC2136ServerError(t *testing.T) {
} }
func TestRFC2136TsigClient(t *testing.T) { func TestRFC2136TsigClient(t *testing.T) {
clearFqdnCache() acme.ClearFqdnCache()
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
@ -102,9 +103,9 @@ func TestRFC2136TsigClient(t *testing.T) {
} }
defer server.Shutdown() defer server.Shutdown()
provider, err := NewDNSProviderRFC2136(addrstr, "", rfc2136TestTsigKey, rfc2136TestTsigSecret) provider, err := NewDNSProvider(addrstr, "", rfc2136TestTsigKey, rfc2136TestTsigSecret)
if err != nil { if err != nil {
t.Fatalf("Expected NewDNSProviderRFC2136() to return no error but the error was -> %v", err) t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
} }
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil { if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil {
t.Errorf("Expected Present() to return no error but the error was -> %v", err) t.Errorf("Expected Present() to return no error but the error was -> %v", err)
@ -112,7 +113,7 @@ func TestRFC2136TsigClient(t *testing.T) {
} }
func TestRFC2136ValidUpdatePacket(t *testing.T) { func TestRFC2136ValidUpdatePacket(t *testing.T) {
clearFqdnCache() acme.ClearFqdnCache()
dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest) dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
@ -134,9 +135,9 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
t.Fatalf("Error packing expect msg: %v", err) t.Fatalf("Error packing expect msg: %v", err)
} }
provider, err := NewDNSProviderRFC2136(addrstr, "", "", "") provider, err := NewDNSProvider(addrstr, "", "", "")
if err != nil { if err != nil {
t.Fatalf("Expected NewDNSProviderRFC2136() to return no error but the error was -> %v", err) t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
} }
if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil { if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil {

View file

@ -1,3 +1,4 @@
// Package route53 implements a DNS provider for solving the DNS-01 challenge using route53 DNS.
package route53 package route53
import ( import (
@ -10,18 +11,18 @@ import (
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
// DNSProviderRoute53 is an implementation of the DNSProvider interface // DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProviderRoute53 struct { type DNSProvider struct {
client *route53.Route53 client *route53.Route53
} }
// NewDNSProviderRoute53 returns a DNSProviderRoute53 instance with a configured route53 client. // NewDNSProvider returns a DNSProvider instance with a configured route53 client.
// Authentication is either done using the passed credentials or - when empty - falling back to // Authentication is either done using the passed credentials or - when empty - falling back to
// the customary AWS credential mechanisms, including the file referenced by $AWS_CREDENTIAL_FILE // the customary AWS credential mechanisms, including the file referenced by $AWS_CREDENTIAL_FILE
// (defaulting to $HOME/.aws/credentials) optionally scoped to $AWS_PROFILE, credentials // (defaulting to $HOME/.aws/credentials) optionally scoped to $AWS_PROFILE, credentials
// supplied by the environment variables AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY [ + AWS_SECURITY_TOKEN ], // supplied by the environment variables AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY [ + AWS_SECURITY_TOKEN ],
// and finally credentials available via the EC2 instance metadata service. // and finally credentials available via the EC2 instance metadata service.
func NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProviderRoute53, error) { func NewDNSProvider(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProvider, error) {
region, ok := aws.Regions[awsRegionName] region, ok := aws.Regions[awsRegionName]
if !ok { if !ok {
return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName) return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName)
@ -39,24 +40,24 @@ func NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*D
} }
client := route53.New(auth, region) client := route53.New(auth, region)
return &DNSProviderRoute53{client: client}, nil return &DNSProvider{client: client}, nil
} }
// Present creates a TXT record using the specified parameters // Present creates a TXT record using the specified parameters
func (r *DNSProviderRoute53) Present(domain, token, keyAuth string) error { func (r *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
value = `"` + value + `"` value = `"` + value + `"`
return r.changeRecord("UPSERT", fqdn, value, ttl) return r.changeRecord("UPSERT", fqdn, value, ttl)
} }
// CleanUp removes the TXT record matching the specified parameters // CleanUp removes the TXT record matching the specified parameters
func (r *DNSProviderRoute53) CleanUp(domain, token, keyAuth string) error { func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
value = `"` + value + `"` value = `"` + value + `"`
return r.changeRecord("DELETE", fqdn, value, ttl) return r.changeRecord("DELETE", fqdn, value, ttl)
} }
func (r *DNSProviderRoute53) changeRecord(action, fqdn, value string, ttl int) error { func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
hostedZoneID, err := r.getHostedZoneID(fqdn) hostedZoneID, err := r.getHostedZoneID(fqdn)
if err != nil { if err != nil {
return err return err
@ -82,7 +83,7 @@ func (r *DNSProviderRoute53) changeRecord(action, fqdn, value string, ttl int) e
}) })
} }
func (r *DNSProviderRoute53) getHostedZoneID(fqdn string) (string, error) { func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
zones := []route53.HostedZone{} zones := []route53.HostedZone{}
zoneResp, err := r.client.ListHostedZones("", 0) zoneResp, err := r.client.ListHostedZones("", 0)
if err != nil { if err != nil {

View file

@ -91,29 +91,29 @@ func makeRoute53TestServer() *testutil.HTTPServer {
return testServer return testServer
} }
func makeRoute53Provider(server *testutil.HTTPServer) *DNSProviderRoute53 { func makeRoute53Provider(server *testutil.HTTPServer) *DNSProvider {
auth := aws.Auth{AccessKey: "abc", SecretKey: "123", Token: ""} auth := aws.Auth{AccessKey: "abc", SecretKey: "123", Token: ""}
client := route53.NewWithClient(auth, aws.Region{Route53Endpoint: server.URL}, testutil.DefaultClient) client := route53.NewWithClient(auth, aws.Region{Route53Endpoint: server.URL}, testutil.DefaultClient)
return &DNSProviderRoute53{client: client} return &DNSProvider{client: client}
} }
func TestNewDNSProviderRoute53Valid(t *testing.T) { func TestNewDNSProviderValid(t *testing.T) {
os.Setenv("AWS_ACCESS_KEY_ID", "") os.Setenv("AWS_ACCESS_KEY_ID", "")
os.Setenv("AWS_SECRET_ACCESS_KEY", "") os.Setenv("AWS_SECRET_ACCESS_KEY", "")
_, err := NewDNSProviderRoute53("123", "123", "us-east-1") _, err := NewDNSProvider("123", "123", "us-east-1")
assert.NoError(t, err) assert.NoError(t, err)
restoreRoute53Env() restoreRoute53Env()
} }
func TestNewDNSProviderRoute53ValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("AWS_ACCESS_KEY_ID", "123") os.Setenv("AWS_ACCESS_KEY_ID", "123")
os.Setenv("AWS_SECRET_ACCESS_KEY", "123") os.Setenv("AWS_SECRET_ACCESS_KEY", "123")
_, err := NewDNSProviderRoute53("", "", "us-east-1") _, err := NewDNSProvider("", "", "us-east-1")
assert.NoError(t, err) assert.NoError(t, err)
restoreRoute53Env() restoreRoute53Env()
} }
func TestNewDNSProviderRoute53MissingAuthErr(t *testing.T) { func TestNewDNSProviderMissingAuthErr(t *testing.T) {
os.Setenv("AWS_ACCESS_KEY_ID", "") os.Setenv("AWS_ACCESS_KEY_ID", "")
os.Setenv("AWS_SECRET_ACCESS_KEY", "") os.Setenv("AWS_SECRET_ACCESS_KEY", "")
os.Setenv("AWS_CREDENTIAL_FILE", "") // in case test machine has this variable set os.Setenv("AWS_CREDENTIAL_FILE", "") // in case test machine has this variable set
@ -124,7 +124,7 @@ func TestNewDNSProviderRoute53MissingAuthErr(t *testing.T) {
awsClient := aws.RetryingClient awsClient := aws.RetryingClient
aws.RetryingClient = &http.Client{Timeout: time.Millisecond} aws.RetryingClient = &http.Client{Timeout: time.Millisecond}
_, err := NewDNSProviderRoute53("", "", "us-east-1") _, err := NewDNSProvider("", "", "us-east-1")
assert.EqualError(t, err, "No valid AWS authentication found") assert.EqualError(t, err, "No valid AWS authentication found")
restoreRoute53Env() restoreRoute53Env()
@ -132,8 +132,8 @@ func TestNewDNSProviderRoute53MissingAuthErr(t *testing.T) {
aws.RetryingClient = awsClient aws.RetryingClient = awsClient
} }
func TestNewDNSProviderRoute53InvalidRegionErr(t *testing.T) { func TestNewDNSProviderInvalidRegionErr(t *testing.T) {
_, err := NewDNSProviderRoute53("123", "123", "us-east-3") _, err := NewDNSProvider("123", "123", "us-east-3")
assert.EqualError(t, err, "Invalid AWS region name us-east-3") assert.EqualError(t, err, "Invalid AWS region name us-east-3")
} }