From 6d8f122a5160f6d9e4c51579f2429dfaa62c7271 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Fri, 16 Feb 2018 06:47:51 -0800 Subject: Upgrading server dependancies (#8308) --- .../lego/providers/dns/auroradns/auroradns.go | 141 ---- .../lego/providers/dns/auroradns/auroradns_test.go | 148 ---- .../xenolf/lego/providers/dns/azure/azure.go | 151 ---- .../xenolf/lego/providers/dns/azure/azure_test.go | 89 -- .../lego/providers/dns/cloudflare/cloudflare.go | 223 ----- .../providers/dns/cloudflare/cloudflare_test.go | 80 -- .../providers/dns/digitalocean/digitalocean.go | 166 ---- .../dns/digitalocean/digitalocean_test.go | 117 --- .../xenolf/lego/providers/dns/dns_providers.go | 86 -- .../lego/providers/dns/dns_providers_test.go | 50 -- .../xenolf/lego/providers/dns/dnsimple/dnsimple.go | 180 ---- .../lego/providers/dns/dnsimple/dnsimple_test.go | 140 --- .../lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go | 248 ------ .../providers/dns/dnsmadeeasy/dnsmadeeasy_test.go | 37 - .../xenolf/lego/providers/dns/dnspod/dnspod.go | 146 ---- .../lego/providers/dns/dnspod/dnspod_test.go | 72 -- .../xenolf/lego/providers/dns/dyn/dyn.go | 274 ------ .../xenolf/lego/providers/dns/dyn/dyn_test.go | 53 -- .../xenolf/lego/providers/dns/exoscale/exoscale.go | 128 --- .../lego/providers/dns/exoscale/exoscale_test.go | 103 --- .../xenolf/lego/providers/dns/gandi/gandi.go | 472 ----------- .../xenolf/lego/providers/dns/gandi/gandi_test.go | 939 --------------------- .../xenolf/lego/providers/dns/godaddy/godaddy.go | 155 ---- .../lego/providers/dns/godaddy/godaddy_test.go | 60 -- .../lego/providers/dns/googlecloud/googlecloud.go | 205 ----- .../providers/dns/googlecloud/googlecloud_test.go | 99 --- .../xenolf/lego/providers/dns/linode/linode.go | 131 --- .../lego/providers/dns/linode/linode_test.go | 317 ------- .../lego/providers/dns/namecheap/namecheap.go | 416 --------- .../lego/providers/dns/namecheap/namecheap_test.go | 402 --------- .../xenolf/lego/providers/dns/ns1/ns1.go | 97 --- .../xenolf/lego/providers/dns/ns1/ns1_test.go | 67 -- .../xenolf/lego/providers/dns/otc/mock.go | 152 ---- .../xenolf/lego/providers/dns/otc/otc.go | 388 --------- .../xenolf/lego/providers/dns/otc/otc_test.go | 112 --- .../xenolf/lego/providers/dns/ovh/ovh.go | 159 ---- .../xenolf/lego/providers/dns/ovh/ovh_test.go | 103 --- .../xenolf/lego/providers/dns/pdns/README.md | 7 - .../xenolf/lego/providers/dns/pdns/pdns.go | 343 -------- .../xenolf/lego/providers/dns/pdns/pdns_test.go | 80 -- .../lego/providers/dns/rackspace/rackspace.go | 284 ------- .../lego/providers/dns/rackspace/rackspace_test.go | 220 ----- .../xenolf/lego/providers/dns/rfc2136/rfc2136.go | 152 ---- .../lego/providers/dns/rfc2136/rfc2136_test.go | 244 ------ .../lego/providers/dns/route53/fixtures_test.go | 39 - .../xenolf/lego/providers/dns/route53/route53.go | 185 ---- .../dns/route53/route53_integration_test.go | 70 -- .../lego/providers/dns/route53/route53_test.go | 105 --- .../lego/providers/dns/route53/testutil_test.go | 38 - .../xenolf/lego/providers/dns/vultr/vultr.go | 127 --- .../xenolf/lego/providers/dns/vultr/vultr_test.go | 65 -- 51 files changed, 8865 deletions(-) delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/azure/azure.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/azure/azure_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dns_providers.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dns_providers_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dyn/dyn.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/dyn/dyn_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/gandi/gandi_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/linode/linode.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/linode/linode_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/ns1/ns1_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/otc/mock.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/otc/otc.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/otc/otc_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/ovh/ovh_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/pdns/README.md delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/pdns/pdns_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/route53/fixtures_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/route53/route53.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/route53/route53_integration_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/route53/route53_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/route53/testutil_test.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/vultr/vultr_test.go (limited to 'vendor/github.com/xenolf/lego/providers/dns') diff --git a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go deleted file mode 100644 index 55b48f9b4..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go +++ /dev/null @@ -1,141 +0,0 @@ -package auroradns - -import ( - "fmt" - "github.com/edeckers/auroradnsclient" - "github.com/edeckers/auroradnsclient/records" - "github.com/edeckers/auroradnsclient/zones" - "github.com/xenolf/lego/acme" - "os" - "sync" -) - -// DNSProvider describes a provider for AuroraDNS -type DNSProvider struct { - recordIDs map[string]string - recordIDsMu sync.Mutex - client *auroradnsclient.AuroraDNSClient -} - -// NewDNSProvider returns a DNSProvider instance configured for AuroraDNS. -// Credentials must be passed in the environment variables: AURORA_USER_ID -// and AURORA_KEY. -func NewDNSProvider() (*DNSProvider, error) { - userID := os.Getenv("AURORA_USER_ID") - key := os.Getenv("AURORA_KEY") - - endpoint := os.Getenv("AURORA_ENDPOINT") - if endpoint == "" { - endpoint = "https://api.auroradns.eu" - } - - return NewDNSProviderCredentials(endpoint, userID, key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for AuroraDNS. -func NewDNSProviderCredentials(baseURL string, userID string, key string) (*DNSProvider, error) { - client, err := auroradnsclient.NewAuroraDNSClient(baseURL, userID, key) - if err != nil { - return nil, err - } - - return &DNSProvider{ - client: client, - recordIDs: make(map[string]string), - }, nil -} - -func (provider *DNSProvider) getZoneInformationByName(name string) (zones.ZoneRecord, error) { - zs, err := provider.client.GetZones() - - if err != nil { - return zones.ZoneRecord{}, err - } - - for _, element := range zs { - if element.Name == name { - return element, nil - } - } - - return zones.ZoneRecord{}, fmt.Errorf("Could not find Zone record") -} - -// Present creates a record with a secret -func (provider *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - // 1. Aurora will happily create the TXT record when it is provided a fqdn, - // but it will only appear in the control panel and will not be - // propagated to DNS servers. Extract and use subdomain instead. - // 2. A trailing dot in the fqdn will cause Aurora to add a trailing dot to - // the subdomain, resulting in _acme-challenge.. rather - // than _acme-challenge. - - subdomain := fqdn[0 : len(fqdn)-len(authZone)-1] - - authZone = acme.UnFqdn(authZone) - - zoneRecord, err := provider.getZoneInformationByName(authZone) - - reqData := - records.CreateRecordRequest{ - RecordType: "TXT", - Name: subdomain, - Content: value, - TTL: 300, - } - - respData, err := provider.client.CreateRecord(zoneRecord.ID, reqData) - if err != nil { - return fmt.Errorf("Could not create record: '%s'.", err) - } - - provider.recordIDsMu.Lock() - provider.recordIDs[fqdn] = respData.ID - provider.recordIDsMu.Unlock() - - return nil -} - -// CleanUp removes a given record that was generated by Present -func (provider *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - provider.recordIDsMu.Lock() - recordID, ok := provider.recordIDs[fqdn] - provider.recordIDsMu.Unlock() - - if !ok { - return fmt.Errorf("Unknown recordID for '%s'", fqdn) - } - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - authZone = acme.UnFqdn(authZone) - - zoneRecord, err := provider.getZoneInformationByName(authZone) - if err != nil { - return err - } - - _, err = provider.client.RemoveRecord(zoneRecord.ID, recordID) - if err != nil { - return err - } - - provider.recordIDsMu.Lock() - delete(provider.recordIDs, fqdn) - provider.recordIDsMu.Unlock() - - return nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go deleted file mode 100644 index f4df7fa61..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package auroradns - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" -) - -var fakeAuroraDNSUserId = "asdf1234" -var fakeAuroraDNSKey = "key" - -func TestAuroraDNSPresent(t *testing.T) { - var requestReceived bool - - mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" && r.URL.Path == "/zones" { - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `[{ - "id": "c56a4180-65aa-42ec-a945-5fd21dec0538", - "name": "example.com" - }]`) - return - } - - requestReceived = true - - if got, want := r.Method, "POST"; got != want { - t.Errorf("Expected method to be '%s' but got '%s'", want, got) - } - - if got, want := r.URL.Path, "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records"; got != want { - t.Errorf("Expected path to be '%s' but got '%s'", want, got) - } - - if got, want := r.Header.Get("Content-Type"), "application/json"; got != want { - t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got) - } - - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Fatalf("Error reading request body: %v", err) - } - - if got, want := string(reqBody), - `{"type":"TXT","name":"_acme-challenge","content":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI","ttl":300}`; got != want { - - t.Errorf("Expected body data to be: `%s` but got `%s`", want, got) - } - - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ - "id": "c56a4180-65aa-42ec-a945-5fd21dec0538", - "type": "TXT", - "name": "_acme-challenge", - "ttl": 300 - }`) - })) - - defer mock.Close() - - auroraProvider, err := NewDNSProviderCredentials(mock.URL, fakeAuroraDNSUserId, fakeAuroraDNSKey) - if auroraProvider == nil { - t.Fatal("Expected non-nil AuroraDNS provider, but was nil") - } - - if err != nil { - t.Fatalf("Expected no error creating provider, but got: %v", err) - } - - err = auroraProvider.Present("example.com", "", "foobar") - if err != nil { - t.Fatalf("Expected no error creating TXT record, but got: %v", err) - } - - if !requestReceived { - t.Error("Expected request to be received by mock backend, but it wasn't") - } -} - -func TestAuroraDNSCleanUp(t *testing.T) { - var requestReceived bool - - mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" && r.URL.Path == "/zones" { - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `[{ - "id": "c56a4180-65aa-42ec-a945-5fd21dec0538", - "name": "example.com" - }]`) - return - } - - if r.Method == "POST" && r.URL.Path == "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records" { - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ - "id": "ec56a4180-65aa-42ec-a945-5fd21dec0538", - "type": "TXT", - "name": "_acme-challenge", - "ttl": 300 - }`) - return - } - - requestReceived = true - - if got, want := r.Method, "DELETE"; got != want { - t.Errorf("Expected method to be '%s' but got '%s'", want, got) - } - - if got, want := r.URL.Path, - "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records/ec56a4180-65aa-42ec-a945-5fd21dec0538"; got != want { - t.Errorf("Expected path to be '%s' but got '%s'", want, got) - } - - if got, want := r.Header.Get("Content-Type"), "application/json"; got != want { - t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got) - } - - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{}`) - })) - defer mock.Close() - - auroraProvider, err := NewDNSProviderCredentials(mock.URL, fakeAuroraDNSUserId, fakeAuroraDNSKey) - if auroraProvider == nil { - t.Fatal("Expected non-nil AuroraDNS provider, but was nil") - } - - if err != nil { - t.Fatalf("Expected no error creating provider, but got: %v", err) - } - - err = auroraProvider.Present("example.com", "", "foobar") - if err != nil { - t.Fatalf("Expected no error creating TXT record, but got: %v", err) - } - - err = auroraProvider.CleanUp("example.com", "", "foobar") - if err != nil { - t.Fatalf("Expected no error removing TXT record, but got: %v", err) - } - - if !requestReceived { - t.Error("Expected request to be received by mock backend, but it wasn't") - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go b/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go deleted file mode 100644 index 6a30b318a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go +++ /dev/null @@ -1,151 +0,0 @@ -// Package azure implements a DNS provider for solving the DNS-01 -// challenge using azure DNS. -// Azure doesn't like trailing dots on domain names, most of the acme code does. -package azure - -import ( - "fmt" - "os" - "time" - - "github.com/Azure/azure-sdk-for-go/arm/dns" - - "strings" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -type DNSProvider struct { - clientId string - clientSecret string - subscriptionId string - tenantId string - resourceGroup string -} - -// NewDNSProvider returns a DNSProvider instance configured for azure. -// Credentials must be passed in the environment variables: AZURE_CLIENT_ID, -// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_RESOURCE_GROUP -func NewDNSProvider() (*DNSProvider, error) { - clientId := os.Getenv("AZURE_CLIENT_ID") - clientSecret := os.Getenv("AZURE_CLIENT_SECRET") - subscriptionId := os.Getenv("AZURE_SUBSCRIPTION_ID") - tenantId := os.Getenv("AZURE_TENANT_ID") - resourceGroup := os.Getenv("AZURE_RESOURCE_GROUP") - return NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for azure. -func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup string) (*DNSProvider, error) { - if clientId == "" || clientSecret == "" || subscriptionId == "" || tenantId == "" || resourceGroup == "" { - return nil, fmt.Errorf("Azure configuration missing") - } - - return &DNSProvider{ - clientId: clientId, - clientSecret: clientSecret, - subscriptionId: subscriptionId, - tenantId: tenantId, - resourceGroup: resourceGroup, - }, 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 -} - -// Present creates a TXT record to fulfil the dns-01 challenge -func (c *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zone, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - rsc := dns.NewRecordSetsClient(c.subscriptionId) - spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint) - rsc.Authorizer = autorest.NewBearerAuthorizer(spt) - - relative := toRelativeRecord(fqdn, acme.ToFqdn(zone)) - rec := dns.RecordSet{ - Name: &relative, - RecordSetProperties: &dns.RecordSetProperties{ - TTL: to.Int64Ptr(60), - TxtRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}}, - }, - } - _, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "") - - if err != nil { - return err - } - - return nil -} - -// Returns the relative record to the domain -func toRelativeRecord(domain, zone string) string { - return acme.UnFqdn(strings.TrimSuffix(domain, zone)) -} - -// CleanUp removes the TXT record matching the specified parameters -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - zone, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - relative := toRelativeRecord(fqdn, acme.ToFqdn(zone)) - rsc := dns.NewRecordSetsClient(c.subscriptionId) - spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint) - rsc.Authorizer = autorest.NewBearerAuthorizer(spt) - _, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "") - if err != nil { - return err - } - - return nil -} - -// Checks that azure has a zone for this domain name. -func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) { - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return "", err - } - - // Now we want to to Azure and get the zone. - spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint) - - dc := dns.NewZonesClient(c.subscriptionId) - dc.Authorizer = autorest.NewBearerAuthorizer(spt) - - zone, err := dc.Get(c.resourceGroup, acme.UnFqdn(authZone)) - - if err != nil { - return "", err - } - - // zone.Name shouldn't have a trailing dot(.) - return to.String(zone.Name), nil -} - -// NewServicePrincipalTokenFromCredentials creates a new ServicePrincipalToken using values of the -// passed credentials map. -func (c *DNSProvider) newServicePrincipalTokenFromCredentials(scope string) (*adal.ServicePrincipalToken, error) { - oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, c.tenantId) - if err != nil { - panic(err) - } - return adal.NewServicePrincipalToken(*oauthConfig, c.clientId, c.clientSecret, scope) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/azure/azure_test.go b/vendor/github.com/xenolf/lego/providers/dns/azure/azure_test.go deleted file mode 100644 index db55f578a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/azure/azure_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package azure - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - azureLiveTest bool - azureClientID string - azureClientSecret string - azureSubscriptionID string - azureTenantID string - azureResourceGroup string - azureDomain string -) - -func init() { - azureClientID = os.Getenv("AZURE_CLIENT_ID") - azureClientSecret = os.Getenv("AZURE_CLIENT_SECRET") - azureSubscriptionID = os.Getenv("AZURE_SUBSCRIPTION_ID") - azureTenantID = os.Getenv("AZURE_TENANT_ID") - azureResourceGroup = os.Getenv("AZURE_RESOURCE_GROUP") - azureDomain = os.Getenv("AZURE_DOMAIN") - if len(azureClientID) > 0 && len(azureClientSecret) > 0 { - azureLiveTest = true - } -} - -func restoreAzureEnv() { - os.Setenv("AZURE_CLIENT_ID", azureClientID) - os.Setenv("AZURE_SUBSCRIPTION_ID", azureSubscriptionID) -} - -func TestNewDNSProviderValid(t *testing.T) { - if !azureLiveTest { - t.Skip("skipping live test (requires credentials)") - } - os.Setenv("AZURE_CLIENT_ID", "") - _, err := NewDNSProviderCredentials(azureClientID, azureClientSecret, azureSubscriptionID, azureTenantID, azureResourceGroup) - assert.NoError(t, err) - restoreAzureEnv() -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - if !azureLiveTest { - t.Skip("skipping live test (requires credentials)") - } - os.Setenv("AZURE_CLIENT_ID", "other") - _, err := NewDNSProvider() - assert.NoError(t, err) - restoreAzureEnv() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("AZURE_SUBSCRIPTION_ID", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "Azure configuration missing") - restoreAzureEnv() -} - -func TestLiveAzurePresent(t *testing.T) { - if !azureLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(azureClientID, azureClientSecret, azureSubscriptionID, azureTenantID, azureResourceGroup) - assert.NoError(t, err) - - err = provider.Present(azureDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveAzureCleanUp(t *testing.T) { - if !azureLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(azureClientID, azureClientSecret, azureSubscriptionID, azureTenantID, azureResourceGroup) - time.Sleep(time.Second * 1) - - assert.NoError(t, err) - - err = provider.CleanUp(azureDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go b/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go deleted file mode 100644 index 84952238d..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go +++ /dev/null @@ -1,223 +0,0 @@ -// Package cloudflare implements a DNS provider for solving the DNS-01 -// challenge using cloudflare DNS. -package cloudflare - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "time" - - "github.com/xenolf/lego/acme" -) - -// CloudFlareAPIURL represents the API endpoint to call. -// TODO: Unexport? -const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4" - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -type DNSProvider struct { - authEmail string - authKey string -} - -// NewDNSProvider returns a DNSProvider instance configured for cloudflare. -// Credentials must be passed in the environment variables: CLOUDFLARE_EMAIL -// and CLOUDFLARE_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - email := os.Getenv("CLOUDFLARE_EMAIL") - key := os.Getenv("CLOUDFLARE_API_KEY") - return NewDNSProviderCredentials(email, key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for cloudflare. -func NewDNSProviderCredentials(email, key string) (*DNSProvider, error) { - if email == "" || key == "" { - return nil, fmt.Errorf("CloudFlare credentials missing") - } - - return &DNSProvider{ - authEmail: email, - authKey: key, - }, 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 -} - -// Present creates a TXT record to fulfil the dns-01 challenge -func (c *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - rec := cloudFlareRecord{ - Type: "TXT", - Name: acme.UnFqdn(fqdn), - Content: value, - TTL: 120, - } - - body, err := json.Marshal(rec) - if err != nil { - return err - } - - _, err = c.makeRequest("POST", fmt.Sprintf("/zones/%s/dns_records", zoneID), bytes.NewReader(body)) - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - record, err := c.findTxtRecord(fqdn) - if err != nil { - return err - } - - _, err = c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil) - if err != nil { - return err - } - - return nil -} - -func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) { - // HostedZone represents a CloudFlare DNS zone - type HostedZone struct { - ID string `json:"id"` - Name string `json:"name"` - } - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return "", err - } - - result, err := c.makeRequest("GET", "/zones?name="+acme.UnFqdn(authZone), nil) - if err != nil { - return "", err - } - - var hostedZone []HostedZone - err = json.Unmarshal(result, &hostedZone) - if err != nil { - return "", err - } - - if len(hostedZone) != 1 { - return "", fmt.Errorf("Zone %s not found in CloudFlare for domain %s", authZone, fqdn) - } - - return hostedZone[0].ID, nil -} - -func (c *DNSProvider) findTxtRecord(fqdn string) (*cloudFlareRecord, error) { - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return nil, err - } - - result, err := c.makeRequest( - "GET", - fmt.Sprintf("/zones/%s/dns_records?per_page=1000&type=TXT&name=%s", zoneID, acme.UnFqdn(fqdn)), - nil, - ) - if err != nil { - return nil, err - } - - var records []cloudFlareRecord - err = json.Unmarshal(result, &records) - if err != nil { - return nil, err - } - - for _, rec := range records { - if rec.Name == acme.UnFqdn(fqdn) { - return &rec, nil - } - } - - return nil, fmt.Errorf("No existing record found for %s", fqdn) -} - -func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) { - // APIError contains error details for failed requests - type APIError struct { - Code int `json:"code,omitempty"` - Message string `json:"message,omitempty"` - ErrorChain []APIError `json:"error_chain,omitempty"` - } - - // APIResponse represents a response from CloudFlare API - type APIResponse struct { - Success bool `json:"success"` - Errors []*APIError `json:"errors"` - Result json.RawMessage `json:"result"` - } - - req, err := http.NewRequest(method, fmt.Sprintf("%s%s", CloudFlareAPIURL, uri), body) - if err != nil { - return nil, err - } - - req.Header.Set("X-Auth-Email", c.authEmail) - req.Header.Set("X-Auth-Key", c.authKey) - //req.Header.Set("User-Agent", userAgent()) - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error querying Cloudflare API -> %v", err) - } - - defer resp.Body.Close() - - var r APIResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, err - } - - if !r.Success { - if len(r.Errors) > 0 { - errStr := "" - for _, apiErr := range r.Errors { - errStr += fmt.Sprintf("\t Error: %d: %s", apiErr.Code, apiErr.Message) - for _, chainErr := range apiErr.ErrorChain { - errStr += fmt.Sprintf("<- %d: %s", chainErr.Code, chainErr.Message) - } - } - return nil, fmt.Errorf("Cloudflare API Error \n%s", errStr) - } - return nil, fmt.Errorf("Cloudflare API error") - } - - return r.Result, nil -} - -// cloudFlareRecord represents a CloudFlare DNS record -type cloudFlareRecord struct { - Name string `json:"name"` - Type string `json:"type"` - Content string `json:"content"` - ID string `json:"id,omitempty"` - TTL int `json:"ttl,omitempty"` - ZoneID string `json:"zone_id,omitempty"` -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare_test.go b/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare_test.go deleted file mode 100644 index 19b5a40b9..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package cloudflare - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - cflareLiveTest bool - cflareEmail string - cflareAPIKey string - cflareDomain string -) - -func init() { - cflareEmail = os.Getenv("CLOUDFLARE_EMAIL") - cflareAPIKey = os.Getenv("CLOUDFLARE_API_KEY") - cflareDomain = os.Getenv("CLOUDFLARE_DOMAIN") - if len(cflareEmail) > 0 && len(cflareAPIKey) > 0 && len(cflareDomain) > 0 { - cflareLiveTest = true - } -} - -func restoreCloudFlareEnv() { - os.Setenv("CLOUDFLARE_EMAIL", cflareEmail) - os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey) -} - -func TestNewDNSProviderValid(t *testing.T) { - os.Setenv("CLOUDFLARE_EMAIL", "") - os.Setenv("CLOUDFLARE_API_KEY", "") - _, err := NewDNSProviderCredentials("123", "123") - assert.NoError(t, err) - restoreCloudFlareEnv() -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("CLOUDFLARE_EMAIL", "test@example.com") - os.Setenv("CLOUDFLARE_API_KEY", "123") - _, err := NewDNSProvider() - assert.NoError(t, err) - restoreCloudFlareEnv() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("CLOUDFLARE_EMAIL", "") - os.Setenv("CLOUDFLARE_API_KEY", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "CloudFlare credentials missing") - restoreCloudFlareEnv() -} - -func TestCloudFlarePresent(t *testing.T) { - if !cflareLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey) - assert.NoError(t, err) - - err = provider.Present(cflareDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestCloudFlareCleanUp(t *testing.T) { - if !cflareLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 2) - - provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey) - assert.NoError(t, err) - - err = provider.CleanUp(cflareDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean.go b/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean.go deleted file mode 100644 index da261b39a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean.go +++ /dev/null @@ -1,166 +0,0 @@ -// Package digitalocean implements a DNS provider for solving the DNS-01 -// challenge using digitalocean DNS. -package digitalocean - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "os" - "sync" - "time" - - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -// that uses DigitalOcean's REST API to manage TXT records for a domain. -type DNSProvider struct { - apiAuthToken string - recordIDs map[string]int - recordIDsMu sync.Mutex -} - -// NewDNSProvider returns a DNSProvider instance configured for Digital -// Ocean. Credentials must be passed in the environment variable: -// DO_AUTH_TOKEN. -func NewDNSProvider() (*DNSProvider, error) { - apiAuthToken := os.Getenv("DO_AUTH_TOKEN") - return NewDNSProviderCredentials(apiAuthToken) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Digital Ocean. -func NewDNSProviderCredentials(apiAuthToken string) (*DNSProvider, error) { - if apiAuthToken == "" { - return nil, fmt.Errorf("DigitalOcean credentials missing") - } - return &DNSProvider{ - apiAuthToken: apiAuthToken, - recordIDs: make(map[string]int), - }, nil -} - -// Present creates a TXT record using the specified parameters -func (d *DNSProvider) Present(domain, token, keyAuth string) error { - // txtRecordRequest represents the request body to DO's API to make a TXT record - type txtRecordRequest struct { - RecordType string `json:"type"` - Name string `json:"name"` - Data string `json:"data"` - } - - // txtRecordResponse represents a response from DO's API after making a TXT record - type txtRecordResponse struct { - DomainRecord struct { - ID int `json:"id"` - Type string `json:"type"` - Name string `json:"name"` - Data string `json:"data"` - } `json:"domain_record"` - } - - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - authZone = acme.UnFqdn(authZone) - - reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, authZone) - reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value} - body, err := json.Marshal(reqData) - if err != nil { - return err - } - - req, err := http.NewRequest("POST", reqURL, bytes.NewReader(body)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken)) - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - var errInfo digitalOceanAPIError - json.NewDecoder(resp.Body).Decode(&errInfo) - return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message) - } - - // Everything looks good; but we'll need the ID later to delete the record - var respData txtRecordResponse - err = json.NewDecoder(resp.Body).Decode(&respData) - if err != nil { - return err - } - d.recordIDsMu.Lock() - d.recordIDs[fqdn] = respData.DomainRecord.ID - d.recordIDsMu.Unlock() - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - // get the record's unique ID from when we created it - d.recordIDsMu.Lock() - recordID, ok := d.recordIDs[fqdn] - d.recordIDsMu.Unlock() - if !ok { - return fmt.Errorf("unknown record ID for '%s'", fqdn) - } - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - authZone = acme.UnFqdn(authZone) - - reqURL := fmt.Sprintf("%s/v2/domains/%s/records/%d", digitalOceanBaseURL, authZone, recordID) - req, err := http.NewRequest("DELETE", reqURL, nil) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken)) - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - var errInfo digitalOceanAPIError - json.NewDecoder(resp.Body).Decode(&errInfo) - return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message) - } - - // Delete record ID from map - d.recordIDsMu.Lock() - delete(d.recordIDs, fqdn) - d.recordIDsMu.Unlock() - - return nil -} - -type digitalOceanAPIError struct { - ID string `json:"id"` - Message string `json:"message"` -} - -var digitalOceanBaseURL = "https://api.digitalocean.com" diff --git a/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean_test.go b/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean_test.go deleted file mode 100644 index 7498508ba..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/digitalocean/digitalocean_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package digitalocean - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" -) - -var fakeDigitalOceanAuth = "asdf1234" - -func TestDigitalOceanPresent(t *testing.T) { - var requestReceived bool - - mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestReceived = true - - if got, want := r.Method, "POST"; got != want { - t.Errorf("Expected method to be '%s' but got '%s'", want, got) - } - if got, want := r.URL.Path, "/v2/domains/example.com/records"; got != want { - t.Errorf("Expected path to be '%s' but got '%s'", want, got) - } - if got, want := r.Header.Get("Content-Type"), "application/json"; got != want { - t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got) - } - if got, want := r.Header.Get("Authorization"), "Bearer asdf1234"; got != want { - t.Errorf("Expected Authorization to be '%s' but got '%s'", want, got) - } - - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Fatalf("Error reading request body: %v", err) - } - if got, want := string(reqBody), `{"type":"TXT","name":"_acme-challenge.example.com.","data":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI"}`; got != want { - t.Errorf("Expected body data to be: `%s` but got `%s`", want, got) - } - - w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ - "domain_record": { - "id": 1234567, - "type": "TXT", - "name": "_acme-challenge", - "data": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI", - "priority": null, - "port": null, - "weight": null - } - }`) - })) - defer mock.Close() - digitalOceanBaseURL = mock.URL - - doprov, err := NewDNSProviderCredentials(fakeDigitalOceanAuth) - if doprov == nil { - t.Fatal("Expected non-nil DigitalOcean provider, but was nil") - } - if err != nil { - t.Fatalf("Expected no error creating provider, but got: %v", err) - } - - err = doprov.Present("example.com", "", "foobar") - if err != nil { - t.Fatalf("Expected no error creating TXT record, but got: %v", err) - } - if !requestReceived { - t.Error("Expected request to be received by mock backend, but it wasn't") - } -} - -func TestDigitalOceanCleanUp(t *testing.T) { - var requestReceived bool - - mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestReceived = true - - if got, want := r.Method, "DELETE"; got != want { - t.Errorf("Expected method to be '%s' but got '%s'", want, got) - } - if got, want := r.URL.Path, "/v2/domains/example.com/records/1234567"; got != want { - t.Errorf("Expected path to be '%s' but got '%s'", want, got) - } - // NOTE: Even though the body is empty, DigitalOcean API docs still show setting this Content-Type... - if got, want := r.Header.Get("Content-Type"), "application/json"; got != want { - t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got) - } - if got, want := r.Header.Get("Authorization"), "Bearer asdf1234"; got != want { - t.Errorf("Expected Authorization to be '%s' but got '%s'", want, got) - } - - w.WriteHeader(http.StatusNoContent) - })) - defer mock.Close() - digitalOceanBaseURL = mock.URL - - doprov, err := NewDNSProviderCredentials(fakeDigitalOceanAuth) - if doprov == nil { - t.Fatal("Expected non-nil DigitalOcean provider, but was nil") - } - if err != nil { - t.Fatalf("Expected no error creating provider, but got: %v", err) - } - - doprov.recordIDsMu.Lock() - doprov.recordIDs["_acme-challenge.example.com."] = 1234567 - doprov.recordIDsMu.Unlock() - - err = doprov.CleanUp("example.com", "", "") - if err != nil { - t.Fatalf("Expected no error removing TXT record, but got: %v", err) - } - if !requestReceived { - t.Error("Expected request to be received by mock backend, but it wasn't") - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go b/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go deleted file mode 100644 index d7530f788..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go +++ /dev/null @@ -1,86 +0,0 @@ -// Factory for DNS providers -package dns - -import ( - "fmt" - - "github.com/xenolf/lego/acme" - "github.com/xenolf/lego/providers/dns/auroradns" - "github.com/xenolf/lego/providers/dns/azure" - "github.com/xenolf/lego/providers/dns/cloudflare" - "github.com/xenolf/lego/providers/dns/digitalocean" - "github.com/xenolf/lego/providers/dns/dnsimple" - "github.com/xenolf/lego/providers/dns/dnsmadeeasy" - "github.com/xenolf/lego/providers/dns/dnspod" - "github.com/xenolf/lego/providers/dns/dyn" - "github.com/xenolf/lego/providers/dns/exoscale" - "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/linode" - "github.com/xenolf/lego/providers/dns/namecheap" - "github.com/xenolf/lego/providers/dns/ns1" - "github.com/xenolf/lego/providers/dns/otc" - "github.com/xenolf/lego/providers/dns/ovh" - "github.com/xenolf/lego/providers/dns/pdns" - "github.com/xenolf/lego/providers/dns/rackspace" - "github.com/xenolf/lego/providers/dns/rfc2136" - "github.com/xenolf/lego/providers/dns/route53" - "github.com/xenolf/lego/providers/dns/vultr" -) - -func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error) { - var err error - var provider acme.ChallengeProvider - switch name { - case "azure": - provider, err = azure.NewDNSProvider() - case "auroradns": - provider, err = auroradns.NewDNSProvider() - case "cloudflare": - provider, err = cloudflare.NewDNSProvider() - case "digitalocean": - provider, err = digitalocean.NewDNSProvider() - case "dnsimple": - provider, err = dnsimple.NewDNSProvider() - case "dnsmadeeasy": - provider, err = dnsmadeeasy.NewDNSProvider() - case "dnspod": - provider, err = dnspod.NewDNSProvider() - case "dyn": - provider, err = dyn.NewDNSProvider() - case "exoscale": - provider, err = exoscale.NewDNSProvider() - case "gandi": - provider, err = gandi.NewDNSProvider() - case "gcloud": - provider, err = googlecloud.NewDNSProvider() - case "godaddy": - provider, err = godaddy.NewDNSProvider() - case "linode": - provider, err = linode.NewDNSProvider() - case "manual": - provider, err = acme.NewDNSProviderManual() - case "namecheap": - provider, err = namecheap.NewDNSProvider() - case "rackspace": - provider, err = rackspace.NewDNSProvider() - case "route53": - provider, err = route53.NewDNSProvider() - case "rfc2136": - provider, err = rfc2136.NewDNSProvider() - case "vultr": - provider, err = vultr.NewDNSProvider() - case "ovh": - provider, err = ovh.NewDNSProvider() - case "pdns": - provider, err = pdns.NewDNSProvider() - case "ns1": - provider, err = ns1.NewDNSProvider() - case "otc": - provider, err = otc.NewDNSProvider() - default: - err = fmt.Errorf("Unrecognised DNS provider: %s", name) - } - return provider, err -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dns_providers_test.go b/vendor/github.com/xenolf/lego/providers/dns/dns_providers_test.go deleted file mode 100644 index 3f87ffd33..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dns_providers_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package dns - -import ( - "os" - "reflect" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/xenolf/lego/providers/dns/exoscale" -) - -var ( - apiKey string - apiSecret string -) - -func init() { - apiSecret = os.Getenv("EXOSCALE_API_SECRET") - apiKey = os.Getenv("EXOSCALE_API_KEY") -} - -func restoreExoscaleEnv() { - os.Setenv("EXOSCALE_API_KEY", apiKey) - os.Setenv("EXOSCALE_API_SECRET", apiSecret) -} - -func TestKnownDNSProviderSuccess(t *testing.T) { - os.Setenv("EXOSCALE_API_KEY", "abc") - os.Setenv("EXOSCALE_API_SECRET", "123") - provider, err := NewDNSChallengeProviderByName("exoscale") - assert.NoError(t, err) - assert.NotNil(t, provider) - if reflect.TypeOf(provider) != reflect.TypeOf(&exoscale.DNSProvider{}) { - t.Errorf("Not loaded correct DNS proviver: %v is not *exoscale.DNSProvider", reflect.TypeOf(provider)) - } - restoreExoscaleEnv() -} - -func TestKnownDNSProviderError(t *testing.T) { - os.Setenv("EXOSCALE_API_KEY", "") - os.Setenv("EXOSCALE_API_SECRET", "") - _, err := NewDNSChallengeProviderByName("exoscale") - assert.Error(t, err) - restoreExoscaleEnv() -} - -func TestUnknownDNSProvider(t *testing.T) { - _, err := NewDNSChallengeProviderByName("foobar") - assert.Error(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go b/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go deleted file mode 100644 index e3fea79ec..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go +++ /dev/null @@ -1,180 +0,0 @@ -// Package dnsimple implements a DNS provider for solving the DNS-01 challenge -// using dnsimple DNS. -package dnsimple - -import ( - "fmt" - "os" - "strconv" - "strings" - - "github.com/dnsimple/dnsimple-go/dnsimple" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface. -type DNSProvider struct { - client *dnsimple.Client -} - -// NewDNSProvider returns a DNSProvider instance configured for dnsimple. -// Credentials must be passed in the environment variables: DNSIMPLE_OAUTH_TOKEN. -// -// See: https://developer.dnsimple.com/v2/#authentication -func NewDNSProvider() (*DNSProvider, error) { - accessToken := os.Getenv("DNSIMPLE_OAUTH_TOKEN") - baseUrl := os.Getenv("DNSIMPLE_BASE_URL") - - return NewDNSProviderCredentials(accessToken, baseUrl) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for dnsimple. -func NewDNSProviderCredentials(accessToken, baseUrl string) (*DNSProvider, error) { - if accessToken == "" { - return nil, fmt.Errorf("DNSimple OAuth token is missing") - } - - client := dnsimple.NewClient(dnsimple.NewOauthTokenCredentials(accessToken)) - client.UserAgent = "lego" - - if baseUrl != "" { - client.BaseURL = baseUrl - } - - return &DNSProvider{client: client}, nil -} - -// 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) - - zoneName, err := c.getHostedZone(domain) - - if err != nil { - return err - } - - accountID, err := c.getAccountID() - if err != nil { - return err - } - - recordAttributes := c.newTxtRecord(zoneName, fqdn, value, ttl) - _, err = c.client.Zones.CreateRecord(accountID, zoneName, *recordAttributes) - if err != nil { - return fmt.Errorf("DNSimple API call failed: %v", err) - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - records, err := c.findTxtRecords(domain, fqdn) - if err != nil { - return err - } - - accountID, err := c.getAccountID() - if err != nil { - return err - } - - for _, rec := range records { - _, err := c.client.Zones.DeleteRecord(accountID, rec.ZoneID, rec.ID) - if err != nil { - return err - } - } - - return nil -} - -func (c *DNSProvider) getHostedZone(domain string) (string, error) { - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return "", err - } - - accountID, err := c.getAccountID() - if err != nil { - return "", err - } - - zoneName := acme.UnFqdn(authZone) - - zones, err := c.client.Zones.ListZones(accountID, &dnsimple.ZoneListOptions{NameLike: zoneName}) - if err != nil { - return "", fmt.Errorf("DNSimple API call failed: %v", err) - } - - var hostedZone dnsimple.Zone - for _, zone := range zones.Data { - if zone.Name == zoneName { - hostedZone = zone - } - } - - if hostedZone.ID == 0 { - return "", fmt.Errorf("Zone %s not found in DNSimple for domain %s", authZone, domain) - - } - - return hostedZone.Name, nil -} - -func (c *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnsimple.ZoneRecord, error) { - zoneName, err := c.getHostedZone(domain) - if err != nil { - return nil, err - } - - accountID, err := c.getAccountID() - if err != nil { - return nil, err - } - - recordName := c.extractRecordName(fqdn, zoneName) - - result, err := c.client.Zones.ListRecords(accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: recordName, Type: "TXT", ListOptions: dnsimple.ListOptions{}}) - if err != nil { - return []dnsimple.ZoneRecord{}, fmt.Errorf("DNSimple API call has failed: %v", err) - } - - return result.Data, nil -} - -func (c *DNSProvider) newTxtRecord(zoneName, fqdn, value string, ttl int) *dnsimple.ZoneRecord { - name := c.extractRecordName(fqdn, zoneName) - - return &dnsimple.ZoneRecord{ - Type: "TXT", - Name: name, - Content: value, - TTL: ttl, - } -} - -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 -} - -func (c *DNSProvider) getAccountID() (string, error) { - whoamiResponse, err := c.client.Identity.Whoami() - if err != nil { - return "", err - } - - if whoamiResponse.Data.Account == nil { - return "", fmt.Errorf("DNSimple user tokens are not supported, please use an account token.") - } - - return strconv.Itoa(whoamiResponse.Data.Account.ID), nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple_test.go b/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple_test.go deleted file mode 100644 index bd35790d7..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package dnsimple - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - dnsimpleLiveTest bool - dnsimpleOauthToken string - dnsimpleDomain string - dnsimpleBaseUrl string -) - -func init() { - dnsimpleOauthToken = os.Getenv("DNSIMPLE_OAUTH_TOKEN") - dnsimpleDomain = os.Getenv("DNSIMPLE_DOMAIN") - dnsimpleBaseUrl = "https://api.sandbox.dnsimple.com" - - if len(dnsimpleOauthToken) > 0 && len(dnsimpleDomain) > 0 { - baseUrl := os.Getenv("DNSIMPLE_BASE_URL") - - if baseUrl != "" { - dnsimpleBaseUrl = baseUrl - } - - dnsimpleLiveTest = true - } -} - -func restoreDNSimpleEnv() { - os.Setenv("DNSIMPLE_OAUTH_TOKEN", dnsimpleOauthToken) - os.Setenv("DNSIMPLE_BASE_URL", dnsimpleBaseUrl) -} - -// -// NewDNSProvider -// - -func TestNewDNSProviderValid(t *testing.T) { - defer restoreDNSimpleEnv() - - os.Setenv("DNSIMPLE_OAUTH_TOKEN", "123") - provider, err := NewDNSProvider() - - assert.NotNil(t, provider) - assert.Equal(t, "lego", provider.client.UserAgent) - assert.NoError(t, err) -} - -func TestNewDNSProviderValidWithBaseUrl(t *testing.T) { - defer restoreDNSimpleEnv() - - os.Setenv("DNSIMPLE_OAUTH_TOKEN", "123") - os.Setenv("DNSIMPLE_BASE_URL", "https://api.dnsimple.test") - provider, err := NewDNSProvider() - - assert.NotNil(t, provider) - assert.NoError(t, err) - - assert.Equal(t, provider.client.BaseURL, "https://api.dnsimple.test") -} - -func TestNewDNSProviderInvalidWithMissingOauthToken(t *testing.T) { - if dnsimpleLiveTest { - t.Skip("skipping test in live mode") - } - - defer restoreDNSimpleEnv() - - provider, err := NewDNSProvider() - - assert.Nil(t, provider) - assert.EqualError(t, err, "DNSimple OAuth token is missing") -} - -// -// NewDNSProviderCredentials -// - -func TestNewDNSProviderCredentialsValid(t *testing.T) { - provider, err := NewDNSProviderCredentials("123", "") - - assert.NotNil(t, provider) - assert.Equal(t, "lego", provider.client.UserAgent) - assert.NoError(t, err) -} - -func TestNewDNSProviderCredentialsValidWithBaseUrl(t *testing.T) { - provider, err := NewDNSProviderCredentials("123", "https://api.dnsimple.test") - - assert.NotNil(t, provider) - assert.NoError(t, err) - - assert.Equal(t, provider.client.BaseURL, "https://api.dnsimple.test") -} - -func TestNewDNSProviderCredentialsInvalidWithMissingOauthToken(t *testing.T) { - provider, err := NewDNSProviderCredentials("", "") - - assert.Nil(t, provider) - assert.EqualError(t, err, "DNSimple OAuth token is missing") -} - -// -// Present -// - -func TestLiveDNSimplePresent(t *testing.T) { - if !dnsimpleLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(dnsimpleOauthToken, dnsimpleBaseUrl) - assert.NoError(t, err) - - err = provider.Present(dnsimpleDomain, "", "123d==") - assert.NoError(t, err) -} - -// -// Cleanup -// - -func TestLiveDNSimpleCleanUp(t *testing.T) { - if !dnsimpleLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProviderCredentials(dnsimpleOauthToken, dnsimpleBaseUrl) - assert.NoError(t, err) - - err = provider.CleanUp(dnsimpleDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go b/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go deleted file mode 100644 index c4363a4eb..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go +++ /dev/null @@ -1,248 +0,0 @@ -package dnsmadeeasy - -import ( - "bytes" - "crypto/hmac" - "crypto/sha1" - "crypto/tls" - "encoding/hex" - "encoding/json" - "fmt" - "net/http" - "os" - "strconv" - "strings" - "time" - - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface that uses -// DNSMadeEasy's DNS API to manage TXT records for a domain. -type DNSProvider struct { - baseURL string - apiKey string - apiSecret string -} - -// Domain holds the DNSMadeEasy API representation of a Domain -type Domain struct { - ID int `json:"id"` - Name string `json:"name"` -} - -// Record holds the DNSMadeEasy API representation of a Domain Record -type Record struct { - ID int `json:"id"` - Type string `json:"type"` - Name string `json:"name"` - Value string `json:"value"` - TTL int `json:"ttl"` - SourceID int `json:"sourceId"` -} - -// NewDNSProvider returns a DNSProvider instance configured for DNSMadeEasy DNS. -// Credentials must be passed in the environment variables: DNSMADEEASY_API_KEY -// and DNSMADEEASY_API_SECRET. -func NewDNSProvider() (*DNSProvider, error) { - dnsmadeeasyAPIKey := os.Getenv("DNSMADEEASY_API_KEY") - dnsmadeeasyAPISecret := os.Getenv("DNSMADEEASY_API_SECRET") - dnsmadeeasySandbox := os.Getenv("DNSMADEEASY_SANDBOX") - - var baseURL string - - sandbox, _ := strconv.ParseBool(dnsmadeeasySandbox) - if sandbox { - baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0" - } else { - baseURL = "https://api.dnsmadeeasy.com/V2.0" - } - - return NewDNSProviderCredentials(baseURL, dnsmadeeasyAPIKey, dnsmadeeasyAPISecret) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for DNSMadeEasy. -func NewDNSProviderCredentials(baseURL, apiKey, apiSecret string) (*DNSProvider, error) { - if baseURL == "" || apiKey == "" || apiSecret == "" { - return nil, fmt.Errorf("DNS Made Easy credentials missing") - } - - return &DNSProvider{ - baseURL: baseURL, - apiKey: apiKey, - apiSecret: apiSecret, - }, nil -} - -// Present creates a TXT record using the specified parameters -func (d *DNSProvider) Present(domainName, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domainName, keyAuth) - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - // fetch the domain details - domain, err := d.getDomain(authZone) - if err != nil { - return err - } - - // create the TXT record - name := strings.Replace(fqdn, "."+authZone, "", 1) - record := &Record{Type: "TXT", Name: name, Value: value, TTL: ttl} - - err = d.createRecord(domain, record) - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT records matching the specified parameters -func (d *DNSProvider) CleanUp(domainName, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domainName, keyAuth) - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - // fetch the domain details - domain, err := d.getDomain(authZone) - if err != nil { - return err - } - - // find matching records - name := strings.Replace(fqdn, "."+authZone, "", 1) - records, err := d.getRecords(domain, name, "TXT") - if err != nil { - return err - } - - // delete records - for _, record := range *records { - err = d.deleteRecord(record) - if err != nil { - return err - } - } - - return nil -} - -func (d *DNSProvider) getDomain(authZone string) (*Domain, error) { - domainName := authZone[0 : len(authZone)-1] - resource := fmt.Sprintf("%s%s", "/dns/managed/name?domainname=", domainName) - - resp, err := d.sendRequest("GET", resource, nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - domain := &Domain{} - err = json.NewDecoder(resp.Body).Decode(&domain) - if err != nil { - return nil, err - } - - return domain, nil -} - -func (d *DNSProvider) getRecords(domain *Domain, recordName, recordType string) (*[]Record, error) { - resource := fmt.Sprintf("%s/%d/%s%s%s%s", "/dns/managed", domain.ID, "records?recordName=", recordName, "&type=", recordType) - - resp, err := d.sendRequest("GET", resource, nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - type recordsResponse struct { - Records *[]Record `json:"data"` - } - - records := &recordsResponse{} - err = json.NewDecoder(resp.Body).Decode(&records) - if err != nil { - return nil, err - } - - return records.Records, nil -} - -func (d *DNSProvider) createRecord(domain *Domain, record *Record) error { - url := fmt.Sprintf("%s/%d/%s", "/dns/managed", domain.ID, "records") - - resp, err := d.sendRequest("POST", url, record) - if err != nil { - return err - } - defer resp.Body.Close() - - return nil -} - -func (d *DNSProvider) deleteRecord(record Record) error { - resource := fmt.Sprintf("%s/%d/%s/%d", "/dns/managed", record.SourceID, "records", record.ID) - - resp, err := d.sendRequest("DELETE", resource, nil) - if err != nil { - return err - } - defer resp.Body.Close() - - return nil -} - -func (d *DNSProvider) sendRequest(method, resource string, payload interface{}) (*http.Response, error) { - url := fmt.Sprintf("%s%s", d.baseURL, resource) - - body, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - timestamp := time.Now().UTC().Format(time.RFC1123) - signature := computeHMAC(timestamp, d.apiSecret) - - req, err := http.NewRequest(method, url, bytes.NewReader(body)) - if err != nil { - return nil, err - } - req.Header.Set("x-dnsme-apiKey", d.apiKey) - req.Header.Set("x-dnsme-requestDate", timestamp) - req.Header.Set("x-dnsme-hmac", signature) - req.Header.Set("accept", "application/json") - req.Header.Set("content-type", "application/json") - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{ - Transport: transport, - Timeout: time.Duration(10 * time.Second), - } - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode > 299 { - return nil, fmt.Errorf("DNSMadeEasy API request failed with HTTP status code %d", resp.StatusCode) - } - - return resp, nil -} - -func computeHMAC(message string, secret string) string { - key := []byte(secret) - h := hmac.New(sha1.New, key) - h.Write([]byte(message)) - return hex.EncodeToString(h.Sum(nil)) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go b/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go deleted file mode 100644 index e860ecb69..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package dnsmadeeasy - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - testLive bool - testAPIKey string - testAPISecret string - testDomain string -) - -func init() { - testAPIKey = os.Getenv("DNSMADEEASY_API_KEY") - testAPISecret = os.Getenv("DNSMADEEASY_API_SECRET") - testDomain = os.Getenv("DNSMADEEASY_DOMAIN") - os.Setenv("DNSMADEEASY_SANDBOX", "true") - testLive = len(testAPIKey) > 0 && len(testAPISecret) > 0 -} - -func TestPresentAndCleanup(t *testing.T) { - if !testLive { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - - err = provider.Present(testDomain, "", "123d==") - assert.NoError(t, err) - - err = provider.CleanUp(testDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go b/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go deleted file mode 100644 index 0ce08a8bb..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go +++ /dev/null @@ -1,146 +0,0 @@ -// Package dnspod implements a DNS provider for solving the DNS-01 challenge -// using dnspod DNS. -package dnspod - -import ( - "fmt" - "os" - "strings" - - "github.com/decker502/dnspod-go" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface. -type DNSProvider struct { - client *dnspod.Client -} - -// NewDNSProvider returns a DNSProvider instance configured for dnspod. -// Credentials must be passed in the environment variables: DNSPOD_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - key := os.Getenv("DNSPOD_API_KEY") - return NewDNSProviderCredentials(key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for dnspod. -func NewDNSProviderCredentials(key string) (*DNSProvider, error) { - if key == "" { - return nil, fmt.Errorf("dnspod credentials missing") - } - - params := dnspod.CommonParams{LoginToken: key, Format: "json"} - return &DNSProvider{ - client: dnspod.NewClient(params), - }, nil -} - -// 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) - zoneID, zoneName, err := c.getHostedZone(domain) - if err != nil { - return err - } - - recordAttributes := c.newTxtRecord(zoneName, fqdn, value, ttl) - _, _, err = c.client.Domains.CreateRecord(zoneID, *recordAttributes) - if err != nil { - return fmt.Errorf("dnspod API call failed: %v", err) - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - records, err := c.findTxtRecords(domain, fqdn) - if err != nil { - return err - } - - zoneID, _, err := c.getHostedZone(domain) - if err != nil { - return err - } - - for _, rec := range records { - _, err := c.client.Domains.DeleteRecord(zoneID, rec.ID) - if err != nil { - return err - } - } - return nil -} - -func (c *DNSProvider) getHostedZone(domain string) (string, string, error) { - zones, _, err := c.client.Domains.List() - if err != nil { - return "", "", fmt.Errorf("dnspod API call failed: %v", err) - } - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return "", "", err - } - - var hostedZone dnspod.Domain - for _, zone := range zones { - if zone.Name == acme.UnFqdn(authZone) { - hostedZone = zone - } - } - - if hostedZone.ID == 0 { - return "", "", fmt.Errorf("Zone %s not found in dnspod for domain %s", authZone, domain) - - } - - return fmt.Sprintf("%v", hostedZone.ID), hostedZone.Name, nil -} - -func (c *DNSProvider) newTxtRecord(zone, fqdn, value string, ttl int) *dnspod.Record { - name := c.extractRecordName(fqdn, zone) - - return &dnspod.Record{ - Type: "TXT", - Name: name, - Value: value, - Line: "默认", - TTL: "600", - } -} - -func (c *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnspod.Record, error) { - zoneID, zoneName, err := c.getHostedZone(domain) - if err != nil { - return nil, err - } - - var records []dnspod.Record - result, _, err := c.client.Domains.ListRecords(zoneID, "") - if err != nil { - return records, fmt.Errorf("dnspod API call has failed: %v", err) - } - - recordName := c.extractRecordName(fqdn, zoneName) - - for _, record := range result { - if record.Name == recordName { - records = append(records, record) - } - } - - return records, nil -} - -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 -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod_test.go b/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod_test.go deleted file mode 100644 index 3311eb0a6..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package dnspod - -import ( - "github.com/stretchr/testify/assert" - "os" - "testing" - "time" -) - -var ( - dnspodLiveTest bool - dnspodAPIKey string - dnspodDomain string -) - -func init() { - dnspodAPIKey = os.Getenv("DNSPOD_API_KEY") - dnspodDomain = os.Getenv("DNSPOD_DOMAIN") - if len(dnspodAPIKey) > 0 && len(dnspodDomain) > 0 { - dnspodLiveTest = true - } -} - -func restorednspodEnv() { - os.Setenv("DNSPOD_API_KEY", dnspodAPIKey) -} - -func TestNewDNSProviderValid(t *testing.T) { - os.Setenv("DNSPOD_API_KEY", "") - _, err := NewDNSProviderCredentials("123") - assert.NoError(t, err) - restorednspodEnv() -} -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("DNSPOD_API_KEY", "123") - _, err := NewDNSProvider() - assert.NoError(t, err) - restorednspodEnv() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("DNSPOD_API_KEY", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "dnspod credentials missing") - restorednspodEnv() -} - -func TestLivednspodPresent(t *testing.T) { - if !dnspodLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(dnspodAPIKey) - assert.NoError(t, err) - - err = provider.Present(dnspodDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestLivednspodCleanUp(t *testing.T) { - if !dnspodLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProviderCredentials(dnspodAPIKey) - assert.NoError(t, err) - - err = provider.CleanUp(dnspodDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn.go b/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn.go deleted file mode 100644 index 384bc850c..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn.go +++ /dev/null @@ -1,274 +0,0 @@ -// Package dyn implements a DNS provider for solving the DNS-01 challenge -// using Dyn Managed DNS. -package dyn - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "os" - "strconv" - "time" - - "github.com/xenolf/lego/acme" -) - -var dynBaseURL = "https://api.dynect.net/REST" - -type dynResponse struct { - // One of 'success', 'failure', or 'incomplete' - Status string `json:"status"` - - // The structure containing the actual results of the request - Data json.RawMessage `json:"data"` - - // The ID of the job that was created in response to a request. - JobID int `json:"job_id"` - - // A list of zero or more messages - Messages json.RawMessage `json:"msgs"` -} - -// DNSProvider is an implementation of the acme.ChallengeProvider interface that uses -// Dyn's Managed DNS API to manage TXT records for a domain. -type DNSProvider struct { - customerName string - userName string - password string - token string -} - -// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS. -// Credentials must be passed in the environment variables: DYN_CUSTOMER_NAME, -// DYN_USER_NAME and DYN_PASSWORD. -func NewDNSProvider() (*DNSProvider, error) { - customerName := os.Getenv("DYN_CUSTOMER_NAME") - userName := os.Getenv("DYN_USER_NAME") - password := os.Getenv("DYN_PASSWORD") - return NewDNSProviderCredentials(customerName, userName, password) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Dyn DNS. -func NewDNSProviderCredentials(customerName, userName, password string) (*DNSProvider, error) { - if customerName == "" || userName == "" || password == "" { - return nil, fmt.Errorf("DynDNS credentials missing") - } - - return &DNSProvider{ - customerName: customerName, - userName: userName, - password: password, - }, nil -} - -func (d *DNSProvider) sendRequest(method, resource string, payload interface{}) (*dynResponse, error) { - url := fmt.Sprintf("%s/%s", dynBaseURL, resource) - - body, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(method, url, bytes.NewReader(body)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - if len(d.token) > 0 { - req.Header.Set("Auth-Token", d.token) - } - - client := &http.Client{Timeout: time.Duration(10 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return nil, fmt.Errorf("Dyn API request failed with HTTP status code %d", resp.StatusCode) - } else if resp.StatusCode == 307 { - // TODO add support for HTTP 307 response and long running jobs - return nil, fmt.Errorf("Dyn API request returned HTTP 307. This is currently unsupported") - } - - var dynRes dynResponse - err = json.NewDecoder(resp.Body).Decode(&dynRes) - if err != nil { - return nil, err - } - - if dynRes.Status == "failure" { - // TODO add better error handling - return nil, fmt.Errorf("Dyn API request failed: %s", dynRes.Messages) - } - - return &dynRes, nil -} - -// Starts a new Dyn API Session. Authenticates using customerName, userName, -// password and receives a token to be used in for subsequent requests. -func (d *DNSProvider) login() error { - type creds struct { - Customer string `json:"customer_name"` - User string `json:"user_name"` - Pass string `json:"password"` - } - - type session struct { - Token string `json:"token"` - Version string `json:"version"` - } - - payload := &creds{Customer: d.customerName, User: d.userName, Pass: d.password} - dynRes, err := d.sendRequest("POST", "Session", payload) - if err != nil { - return err - } - - var s session - err = json.Unmarshal(dynRes.Data, &s) - if err != nil { - return err - } - - d.token = s.Token - - return nil -} - -// Destroys Dyn Session -func (d *DNSProvider) logout() error { - if len(d.token) == 0 { - // nothing to do - return nil - } - - url := fmt.Sprintf("%s/Session", dynBaseURL) - req, err := http.NewRequest("DELETE", url, nil) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Auth-Token", d.token) - - client := &http.Client{Timeout: time.Duration(10 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return err - } - resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("Dyn API request failed to delete session with HTTP status code %d", resp.StatusCode) - } - - d.token = "" - - return nil -} - -// Present creates a TXT record using the specified parameters -func (d *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - err = d.login() - if err != nil { - return err - } - - data := map[string]interface{}{ - "rdata": map[string]string{ - "txtdata": value, - }, - "ttl": strconv.Itoa(ttl), - } - - resource := fmt.Sprintf("TXTRecord/%s/%s/", authZone, fqdn) - _, err = d.sendRequest("POST", resource, data) - if err != nil { - return err - } - - err = d.publish(authZone, "Added TXT record for ACME dns-01 challenge using lego client") - if err != nil { - return err - } - - err = d.logout() - if err != nil { - return err - } - - return nil -} - -func (d *DNSProvider) publish(zone, notes string) error { - type publish struct { - Publish bool `json:"publish"` - Notes string `json:"notes"` - } - - pub := &publish{Publish: true, Notes: notes} - resource := fmt.Sprintf("Zone/%s/", zone) - _, err := d.sendRequest("PUT", resource, pub) - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - err = d.login() - if err != nil { - return err - } - - resource := fmt.Sprintf("TXTRecord/%s/%s/", authZone, fqdn) - url := fmt.Sprintf("%s/%s", dynBaseURL, resource) - req, err := http.NewRequest("DELETE", url, nil) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Auth-Token", d.token) - - client := &http.Client{Timeout: time.Duration(10 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return err - } - resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("Dyn API request failed to delete TXT record HTTP status code %d", resp.StatusCode) - } - - err = d.publish(authZone, "Removed TXT record for ACME dns-01 challenge using lego client") - if err != nil { - return err - } - - err = d.logout() - if err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn_test.go b/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn_test.go deleted file mode 100644 index 0d28d5d0e..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/dyn/dyn_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package dyn - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - dynLiveTest bool - dynCustomerName string - dynUserName string - dynPassword string - dynDomain string -) - -func init() { - dynCustomerName = os.Getenv("DYN_CUSTOMER_NAME") - dynUserName = os.Getenv("DYN_USER_NAME") - dynPassword = os.Getenv("DYN_PASSWORD") - dynDomain = os.Getenv("DYN_DOMAIN") - if len(dynCustomerName) > 0 && len(dynUserName) > 0 && len(dynPassword) > 0 && len(dynDomain) > 0 { - dynLiveTest = true - } -} - -func TestLiveDynPresent(t *testing.T) { - if !dynLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(dynDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveDynCleanUp(t *testing.T) { - if !dynLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(dynDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go b/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go deleted file mode 100644 index 4b125e8df..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go +++ /dev/null @@ -1,128 +0,0 @@ -// Package exoscale implements a DNS provider for solving the DNS-01 challenge -// using exoscale DNS. -package exoscale - -import ( - "errors" - "fmt" - "os" - - "github.com/exoscale/egoscale" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface. -type DNSProvider struct { - client *egoscale.Client -} - -// Credentials must be passed in the environment variables: -// EXOSCALE_API_KEY, EXOSCALE_API_SECRET, EXOSCALE_ENDPOINT. -func NewDNSProvider() (*DNSProvider, error) { - key := os.Getenv("EXOSCALE_API_KEY") - secret := os.Getenv("EXOSCALE_API_SECRET") - endpoint := os.Getenv("EXOSCALE_ENDPOINT") - return NewDNSProviderClient(key, secret, endpoint) -} - -// Uses the supplied parameters to return a DNSProvider instance -// configured for Exoscale. -func NewDNSProviderClient(key, secret, endpoint string) (*DNSProvider, error) { - if key == "" || secret == "" { - return nil, fmt.Errorf("Exoscale credentials missing") - } - if endpoint == "" { - endpoint = "https://api.exoscale.ch/dns" - } - - return &DNSProvider{ - client: egoscale.NewClient(endpoint, key, secret), - }, nil -} - -// 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) - zone, recordName, err := c.FindZoneAndRecordName(fqdn, domain) - if err != nil { - return err - } - - recordID, err := c.FindExistingRecordId(zone, recordName) - if err != nil { - return err - } - - record := egoscale.DNSRecord{ - Name: recordName, - TTL: ttl, - Content: value, - RecordType: "TXT", - } - - if recordID == 0 { - _, err := c.client.CreateRecord(zone, record) - if err != nil { - return errors.New("Error while creating DNS record: " + err.Error()) - } - } else { - record.ID = recordID - _, err := c.client.UpdateRecord(zone, record) - if err != nil { - return errors.New("Error while updating DNS record: " + err.Error()) - } - } - - return nil -} - -// CleanUp removes the record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - zone, recordName, err := c.FindZoneAndRecordName(fqdn, domain) - if err != nil { - return err - } - - recordID, err := c.FindExistingRecordId(zone, recordName) - if err != nil { - return err - } - - if recordID != 0 { - err = c.client.DeleteRecord(zone, recordID) - if err != nil { - return errors.New("Error while deleting DNS record: " + err.Error()) - } - } - - return nil -} - -// Query Exoscale to find an existing record for this name. -// Returns nil if no record could be found -func (c *DNSProvider) FindExistingRecordId(zone, recordName string) (int64, error) { - records, err := c.client.GetRecords(zone) - if err != nil { - return -1, errors.New("Error while retrievening DNS records: " + err.Error()) - } - for _, record := range records { - if record.Name == recordName { - return record.ID, nil - } - } - return 0, nil -} - -// Extract DNS zone and DNS entry name -func (c *DNSProvider) FindZoneAndRecordName(fqdn, domain string) (string, string, error) { - zone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return "", "", err - } - zone = acme.UnFqdn(zone) - name := acme.UnFqdn(fqdn) - name = name[:len(name)-len("."+zone)] - - return zone, name, nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale_test.go b/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale_test.go deleted file mode 100644 index 343dd56f8..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package exoscale - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - exoscaleLiveTest bool - exoscaleAPIKey string - exoscaleAPISecret string - exoscaleDomain string -) - -func init() { - exoscaleAPISecret = os.Getenv("EXOSCALE_API_SECRET") - exoscaleAPIKey = os.Getenv("EXOSCALE_API_KEY") - exoscaleDomain = os.Getenv("EXOSCALE_DOMAIN") - if len(exoscaleAPIKey) > 0 && len(exoscaleAPISecret) > 0 && len(exoscaleDomain) > 0 { - exoscaleLiveTest = true - } -} - -func restoreExoscaleEnv() { - os.Setenv("EXOSCALE_API_KEY", exoscaleAPIKey) - os.Setenv("EXOSCALE_API_SECRET", exoscaleAPISecret) -} - -func TestNewDNSProviderValid(t *testing.T) { - os.Setenv("EXOSCALE_API_KEY", "") - os.Setenv("EXOSCALE_API_SECRET", "") - _, err := NewDNSProviderClient("example@example.com", "123", "") - assert.NoError(t, err) - restoreExoscaleEnv() -} -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("EXOSCALE_API_KEY", "example@example.com") - os.Setenv("EXOSCALE_API_SECRET", "123") - _, err := NewDNSProvider() - assert.NoError(t, err) - restoreExoscaleEnv() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("EXOSCALE_API_KEY", "") - os.Setenv("EXOSCALE_API_SECRET", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "Exoscale credentials missing") - restoreExoscaleEnv() -} - -func TestExtractRootRecordName(t *testing.T) { - provider, err := NewDNSProviderClient("example@example.com", "123", "") - assert.NoError(t, err) - - zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.bar.com.", "bar.com") - assert.NoError(t, err) - assert.Equal(t, "bar.com", zone) - assert.Equal(t, "_acme-challenge", recordName) -} - -func TestExtractSubRecordName(t *testing.T) { - provider, err := NewDNSProviderClient("example@example.com", "123", "") - assert.NoError(t, err) - - zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.foo.bar.com.", "foo.bar.com") - assert.NoError(t, err) - assert.Equal(t, "bar.com", zone) - assert.Equal(t, "_acme-challenge.foo", recordName) -} - -func TestLiveExoscalePresent(t *testing.T) { - if !exoscaleLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderClient(exoscaleAPIKey, exoscaleAPISecret, "") - assert.NoError(t, err) - - err = provider.Present(exoscaleDomain, "", "123d==") - assert.NoError(t, err) - - // Present Twice to handle create / update - err = provider.Present(exoscaleDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveExoscaleCleanUp(t *testing.T) { - if !exoscaleLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProviderClient(exoscaleAPIKey, exoscaleAPISecret, "") - assert.NoError(t, err) - - err = provider.CleanUp(exoscaleDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go b/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go deleted file mode 100644 index 422b02a21..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go +++ /dev/null @@ -1,472 +0,0 @@ -// Package gandi implements a DNS provider for solving the DNS-01 -// challenge using Gandi DNS. -package gandi - -import ( - "bytes" - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "strings" - "sync" - "time" - - "github.com/xenolf/lego/acme" -) - -// Gandi API reference: http://doc.rpc.gandi.net/index.html -// Gandi API domain examples: http://doc.rpc.gandi.net/domain/faq.html - -var ( - // endpoint is the Gandi XML-RPC endpoint used by Present and - // CleanUp. It is overridden during tests. - endpoint = "https://rpc.gandi.net/xmlrpc/" - // findZoneByFqdn determines the DNS zone of an fqdn. It is overridden - // during tests. - findZoneByFqdn = acme.FindZoneByFqdn -) - -// inProgressInfo contains information about an in-progress challenge -type inProgressInfo struct { - zoneID int // zoneID of gandi zone to restore in CleanUp - newZoneID int // zoneID of temporary gandi zone containing TXT record - authZone string // the domain name registered at gandi with trailing "." -} - -// DNSProvider is an implementation of the -// acme.ChallengeProviderTimeout interface that uses Gandi's XML-RPC -// API to manage TXT records for a domain. -type DNSProvider struct { - apiKey string - inProgressFQDNs map[string]inProgressInfo - inProgressAuthZones map[string]struct{} - inProgressMu sync.Mutex -} - -// NewDNSProvider returns a DNSProvider instance configured for Gandi. -// Credentials must be passed in the environment variable: GANDI_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - apiKey := os.Getenv("GANDI_API_KEY") - return NewDNSProviderCredentials(apiKey) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Gandi. -func NewDNSProviderCredentials(apiKey string) (*DNSProvider, error) { - if apiKey == "" { - return nil, fmt.Errorf("No Gandi API Key given") - } - return &DNSProvider{ - apiKey: apiKey, - inProgressFQDNs: make(map[string]inProgressInfo), - inProgressAuthZones: make(map[string]struct{}), - }, nil -} - -// Present creates a TXT record using the specified parameters. It -// does this by creating and activating a new temporary Gandi DNS -// zone. This new zone contains the TXT record. -func (d *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - if ttl < 300 { - ttl = 300 // 300 is gandi minimum value for ttl - } - // find authZone and Gandi zone_id for fqdn - authZone, err := findZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Gandi DNS: findZoneByFqdn failure: %v", err) - } - zoneID, err := d.getZoneID(authZone) - if err != nil { - return err - } - // determine name of TXT record - if !strings.HasSuffix( - strings.ToLower(fqdn), strings.ToLower("."+authZone)) { - return fmt.Errorf( - "Gandi DNS: unexpected authZone %s for fqdn %s", authZone, fqdn) - } - name := fqdn[:len(fqdn)-len("."+authZone)] - // acquire lock and check there is not a challenge already in - // progress for this value of authZone - d.inProgressMu.Lock() - defer d.inProgressMu.Unlock() - if _, ok := d.inProgressAuthZones[authZone]; ok { - return fmt.Errorf( - "Gandi DNS: challenge already in progress for authZone %s", - authZone) - } - // perform API actions to create and activate new gandi zone - // containing the required TXT record - newZoneName := fmt.Sprintf( - "%s [ACME Challenge %s]", - acme.UnFqdn(authZone), time.Now().Format(time.RFC822Z)) - newZoneID, err := d.cloneZone(zoneID, newZoneName) - if err != nil { - return err - } - newZoneVersion, err := d.newZoneVersion(newZoneID) - if err != nil { - return err - } - err = d.addTXTRecord(newZoneID, newZoneVersion, name, value, ttl) - if err != nil { - return err - } - err = d.setZoneVersion(newZoneID, newZoneVersion) - if err != nil { - return err - } - err = d.setZone(authZone, newZoneID) - if err != nil { - return err - } - // save data necessary for CleanUp - d.inProgressFQDNs[fqdn] = inProgressInfo{ - zoneID: zoneID, - newZoneID: newZoneID, - authZone: authZone, - } - d.inProgressAuthZones[authZone] = struct{}{} - return nil -} - -// CleanUp removes the TXT record matching the specified -// parameters. It does this by restoring the old Gandi DNS zone and -// removing the temporary one created by Present. -func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - // acquire lock and retrieve zoneID, newZoneID and authZone - d.inProgressMu.Lock() - defer d.inProgressMu.Unlock() - if _, ok := d.inProgressFQDNs[fqdn]; !ok { - // if there is no cleanup information then just return - return nil - } - zoneID := d.inProgressFQDNs[fqdn].zoneID - newZoneID := d.inProgressFQDNs[fqdn].newZoneID - authZone := d.inProgressFQDNs[fqdn].authZone - delete(d.inProgressFQDNs, fqdn) - delete(d.inProgressAuthZones, authZone) - // perform API actions to restore old gandi zone for authZone - err := d.setZone(authZone, zoneID) - if err != nil { - return err - } - err = d.deleteZone(newZoneID) - if err != nil { - return err - } - return nil -} - -// Timeout returns the values (40*time.Minute, 60*time.Second) which -// are used by the acme package as timeout and check interval values -// when checking for DNS record propagation with Gandi. -func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { - return 40 * time.Minute, 60 * time.Second -} - -// types for XML-RPC method calls and parameters - -type param interface { - param() -} -type paramString struct { - XMLName xml.Name `xml:"param"` - Value string `xml:"value>string"` -} -type paramInt struct { - XMLName xml.Name `xml:"param"` - Value int `xml:"value>int"` -} - -type structMember interface { - structMember() -} -type structMemberString struct { - Name string `xml:"name"` - Value string `xml:"value>string"` -} -type structMemberInt struct { - Name string `xml:"name"` - Value int `xml:"value>int"` -} -type paramStruct struct { - XMLName xml.Name `xml:"param"` - StructMembers []structMember `xml:"value>struct>member"` -} - -func (p paramString) param() {} -func (p paramInt) param() {} -func (m structMemberString) structMember() {} -func (m structMemberInt) structMember() {} -func (p paramStruct) param() {} - -type methodCall struct { - XMLName xml.Name `xml:"methodCall"` - MethodName string `xml:"methodName"` - Params []param `xml:"params"` -} - -// types for XML-RPC responses - -type response interface { - faultCode() int - faultString() string -} - -type responseFault struct { - FaultCode int `xml:"fault>value>struct>member>value>int"` - FaultString string `xml:"fault>value>struct>member>value>string"` -} - -func (r responseFault) faultCode() int { return r.FaultCode } -func (r responseFault) faultString() string { return r.FaultString } - -type responseStruct struct { - responseFault - StructMembers []struct { - Name string `xml:"name"` - ValueInt int `xml:"value>int"` - } `xml:"params>param>value>struct>member"` -} - -type responseInt struct { - responseFault - Value int `xml:"params>param>value>int"` -} - -type responseBool struct { - responseFault - Value bool `xml:"params>param>value>boolean"` -} - -// POSTing/Marshalling/Unmarshalling - -type rpcError struct { - faultCode int - faultString string -} - -func (e rpcError) Error() string { - return fmt.Sprintf( - "Gandi DNS: RPC Error: (%d) %s", e.faultCode, e.faultString) -} - -func httpPost(url string, bodyType string, body io.Reader) ([]byte, error) { - client := http.Client{Timeout: 60 * time.Second} - resp, err := client.Post(url, bodyType, body) - if err != nil { - return nil, fmt.Errorf("Gandi DNS: HTTP Post Error: %v", err) - } - defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Gandi DNS: HTTP Post Error: %v", err) - } - return b, nil -} - -// rpcCall makes an XML-RPC call to Gandi's RPC endpoint by -// marshalling the data given in the call argument to XML and sending -// that via HTTP Post to Gandi. The response is then unmarshalled into -// the resp argument. -func rpcCall(call *methodCall, resp response) error { - // marshal - b, err := xml.MarshalIndent(call, "", " ") - if err != nil { - return fmt.Errorf("Gandi DNS: Marshal Error: %v", err) - } - // post - b = append([]byte(``+"\n"), b...) - respBody, err := httpPost(endpoint, "text/xml", bytes.NewReader(b)) - if err != nil { - return err - } - // unmarshal - err = xml.Unmarshal(respBody, resp) - if err != nil { - return fmt.Errorf("Gandi DNS: Unmarshal Error: %v", err) - } - if resp.faultCode() != 0 { - return rpcError{ - faultCode: resp.faultCode(), faultString: resp.faultString()} - } - return nil -} - -// functions to perform API actions - -func (d *DNSProvider) getZoneID(domain string) (int, error) { - resp := &responseStruct{} - err := rpcCall(&methodCall{ - MethodName: "domain.info", - Params: []param{ - paramString{Value: d.apiKey}, - paramString{Value: domain}, - }, - }, resp) - if err != nil { - return 0, err - } - var zoneID int - for _, member := range resp.StructMembers { - if member.Name == "zone_id" { - zoneID = member.ValueInt - } - } - if zoneID == 0 { - return 0, fmt.Errorf( - "Gandi DNS: Could not determine zone_id for %s", domain) - } - return zoneID, nil -} - -func (d *DNSProvider) cloneZone(zoneID int, name string) (int, error) { - resp := &responseStruct{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.clone", - Params: []param{ - paramString{Value: d.apiKey}, - paramInt{Value: zoneID}, - paramInt{Value: 0}, - paramStruct{ - StructMembers: []structMember{ - structMemberString{ - Name: "name", - Value: name, - }}, - }, - }, - }, resp) - if err != nil { - return 0, err - } - var newZoneID int - for _, member := range resp.StructMembers { - if member.Name == "id" { - newZoneID = member.ValueInt - } - } - if newZoneID == 0 { - return 0, fmt.Errorf("Gandi DNS: Could not determine cloned zone_id") - } - return newZoneID, nil -} - -func (d *DNSProvider) newZoneVersion(zoneID int) (int, error) { - resp := &responseInt{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.version.new", - Params: []param{ - paramString{Value: d.apiKey}, - paramInt{Value: zoneID}, - }, - }, resp) - if err != nil { - return 0, err - } - if resp.Value == 0 { - return 0, fmt.Errorf("Gandi DNS: Could not create new zone version") - } - return resp.Value, nil -} - -func (d *DNSProvider) addTXTRecord(zoneID int, version int, name string, value string, ttl int) error { - resp := &responseStruct{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.record.add", - Params: []param{ - paramString{Value: d.apiKey}, - paramInt{Value: zoneID}, - paramInt{Value: version}, - paramStruct{ - StructMembers: []structMember{ - structMemberString{ - Name: "type", - Value: "TXT", - }, structMemberString{ - Name: "name", - Value: name, - }, structMemberString{ - Name: "value", - Value: value, - }, structMemberInt{ - Name: "ttl", - Value: ttl, - }}, - }, - }, - }, resp) - if err != nil { - return err - } - return nil -} - -func (d *DNSProvider) setZoneVersion(zoneID int, version int) error { - resp := &responseBool{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.version.set", - Params: []param{ - paramString{Value: d.apiKey}, - paramInt{Value: zoneID}, - paramInt{Value: version}, - }, - }, resp) - if err != nil { - return err - } - if !resp.Value { - return fmt.Errorf("Gandi DNS: could not set zone version") - } - return nil -} - -func (d *DNSProvider) setZone(domain string, zoneID int) error { - resp := &responseStruct{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.set", - Params: []param{ - paramString{Value: d.apiKey}, - paramString{Value: domain}, - paramInt{Value: zoneID}, - }, - }, resp) - if err != nil { - return err - } - var respZoneID int - for _, member := range resp.StructMembers { - if member.Name == "zone_id" { - respZoneID = member.ValueInt - } - } - if respZoneID != zoneID { - return fmt.Errorf( - "Gandi DNS: Could not set new zone_id for %s", domain) - } - return nil -} - -func (d *DNSProvider) deleteZone(zoneID int) error { - resp := &responseBool{} - err := rpcCall(&methodCall{ - MethodName: "domain.zone.delete", - Params: []param{ - paramString{Value: d.apiKey}, - paramInt{Value: zoneID}, - }, - }, resp) - if err != nil { - return err - } - if !resp.Value { - return fmt.Errorf("Gandi DNS: could not delete zone_id") - } - return nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi_test.go b/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi_test.go deleted file mode 100644 index 451333ca1..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/gandi/gandi_test.go +++ /dev/null @@ -1,939 +0,0 @@ -package gandi - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "regexp" - "strings" - "testing" - - "github.com/xenolf/lego/acme" -) - -// stagingServer is the Let's Encrypt staging server used by the live test -const stagingServer = "https://acme-staging.api.letsencrypt.org/directory" - -// user implements acme.User and is used by the live test -type user struct { - Email string - Registration *acme.RegistrationResource - key crypto.PrivateKey -} - -func (u *user) GetEmail() string { - return u.Email -} -func (u *user) GetRegistration() *acme.RegistrationResource { - return u.Registration -} -func (u *user) GetPrivateKey() crypto.PrivateKey { - return u.key -} - -// TestDNSProvider runs Present and CleanUp against a fake Gandi RPC -// Server, whose responses are predetermined for particular requests. -func TestDNSProvider(t *testing.T) { - fakeAPIKey := "123412341234123412341234" - fakeKeyAuth := "XXXX" - provider, err := NewDNSProviderCredentials(fakeAPIKey) - if err != nil { - t.Fatal(err) - } - regexpDate, err := regexp.Compile(`\[ACME Challenge [^\]:]*:[^\]]*\]`) - if err != nil { - t.Fatal(err) - } - // start fake RPC server - fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Content-Type") != "text/xml" { - t.Fatalf("Content-Type: text/xml header not found") - } - req, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Fatal(err) - } - req = regexpDate.ReplaceAllLiteral( - req, []byte(`[ACME Challenge 01 Jan 16 00:00 +0000]`)) - resp, ok := serverResponses[string(req)] - if !ok { - t.Fatalf("Server response for request not found") - } - _, err = io.Copy(w, strings.NewReader(resp)) - if err != nil { - t.Fatal(err) - } - })) - defer fakeServer.Close() - // define function to override findZoneByFqdn with - fakeFindZoneByFqdn := func(fqdn string, nameserver []string) (string, error) { - return "example.com.", nil - } - // override gandi endpoint and findZoneByFqdn function - savedEndpoint, savedFindZoneByFqdn := endpoint, findZoneByFqdn - defer func() { - endpoint, findZoneByFqdn = savedEndpoint, savedFindZoneByFqdn - }() - endpoint, findZoneByFqdn = fakeServer.URL+"/", fakeFindZoneByFqdn - // run Present - err = provider.Present("abc.def.example.com", "", fakeKeyAuth) - if err != nil { - t.Fatal(err) - } - // run CleanUp - err = provider.CleanUp("abc.def.example.com", "", fakeKeyAuth) - if err != nil { - t.Fatal(err) - } -} - -// TestDNSProviderLive performs a live test to obtain a certificate -// using the Let's Encrypt staging server. It runs provided that both -// the environment variables GANDI_API_KEY and GANDI_TEST_DOMAIN are -// set. Otherwise the test is skipped. -// -// To complete this test, go test must be run with the -timeout=40m -// flag, since the default timeout of 10m is insufficient. -func TestDNSProviderLive(t *testing.T) { - apiKey := os.Getenv("GANDI_API_KEY") - domain := os.Getenv("GANDI_TEST_DOMAIN") - if apiKey == "" || domain == "" { - t.Skip("skipping live test") - } - // create a user. - const rsaKeySize = 2048 - privateKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize) - if err != nil { - t.Fatal(err) - } - myUser := user{ - Email: "test@example.com", - key: privateKey, - } - // create a client using staging server - client, err := acme.NewClient(stagingServer, &myUser, acme.RSA2048) - if err != nil { - t.Fatal(err) - } - provider, err := NewDNSProviderCredentials(apiKey) - if err != nil { - t.Fatal(err) - } - err = client.SetChallengeProvider(acme.DNS01, provider) - if err != nil { - t.Fatal(err) - } - client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.TLSSNI01}) - // register and agree tos - reg, err := client.Register() - if err != nil { - t.Fatal(err) - } - myUser.Registration = reg - err = client.AgreeToTOS() - if err != nil { - t.Fatal(err) - } - // complete the challenge - bundle := false - _, failures := client.ObtainCertificate([]string{domain}, bundle, nil, false) - if len(failures) > 0 { - t.Fatal(failures) - } -} - -// serverResponses is the XML-RPC Request->Response map used by the -// fake RPC server. It was generated by recording a real RPC session -// which resulted in the successful issue of a cert, and then -// anonymizing the RPC data. -var serverResponses = map[string]string{ - // Present Request->Response 1 (getZoneID) - ` - - domain.info - - - 123412341234123412341234 - - - - - example.com. - - -`: ` - - - - - -date_updated -20160216T16:14:23 - - -date_delete -20170331T16:04:06 - - -is_premium -0 - - -date_hold_begin -20170215T02:04:06 - - -date_registry_end -20170215T02:04:06 - - -authinfo_expiration_date -20161211T21:31:20 - - -contacts - - -owner - - -handle -LEGO-GANDI - - -id -111111 - - - - -admin - - -handle -LEGO-GANDI - - -id -111111 - - - - -bill - - -handle -LEGO-GANDI - - -id -111111 - - - - -tech - - -handle -LEGO-GANDI - - -id -111111 - - - - -reseller - - - - -nameservers - -a.dns.gandi.net -b.dns.gandi.net -c.dns.gandi.net - - - -date_restore_end -20170501T02:04:06 - - -id -2222222 - - -authinfo -ABCDABCDAB - - -status - -clientTransferProhibited -serverTransferProhibited - - - -tags - - - - -date_hold_end -20170401T02:04:06 - - -services - -gandidns -gandimail - - - -date_pending_delete_end -20170506T02:04:06 - - -zone_id -1234567 - - -date_renew_begin -20120101T00:00:00 - - -fqdn -example.com - - -autorenew - - -date_registry_creation -20150215T02:04:06 - - -tld -org - - -date_created -20150215T03:04:06 - - - - - -`, - // Present Request->Response 2 (cloneZone) - ` - - domain.zone.clone - - - 123412341234123412341234 - - - - - 1234567 - - - - - 0 - - - - - - - name - - example.com [ACME Challenge 01 Jan 16 00:00 +0000] - - - - - -`: ` - - - - - -name -example.com [ACME Challenge 01 Jan 16 00:00 +0000] - - -versions - -1 - - - -date_updated -20160216T16:24:29 - - -id -7654321 - - -owner -LEGO-GANDI - - -version -1 - - -domains -0 - - -public -0 - - - - - -`, - // Present Request->Response 3 (newZoneVersion) - ` - - domain.zone.version.new - - - 123412341234123412341234 - - - - - 7654321 - - -`: ` - - - -2 - - - -`, - // Present Request->Response 4 (addTXTRecord) - ` - - domain.zone.record.add - - - 123412341234123412341234 - - - - - 7654321 - - - - - 2 - - - - - - - type - - TXT - - - - name - - _acme-challenge.abc.def - - - - value - - ezRpBPY8wH8djMLYjX2uCKPwiKDkFZ1SFMJ6ZXGlHrQ - - - - ttl - - 300 - - - - - -`: ` - - - - - -name -_acme-challenge.abc.def - - -type -TXT - - -id -333333333 - - -value -"ezRpBPY8wH8djMLYjX2uCKPwiKDkFZ1SFMJ6ZXGlHrQ" - - -ttl -300 - - - - - -`, - // Present Request->Response 5 (setZoneVersion) - ` - - domain.zone.version.set - - - 123412341234123412341234 - - - - - 7654321 - - - - - 2 - - -`: ` - - - -1 - - - -`, - // Present Request->Response 6 (setZone) - ` - - domain.zone.set - - - 123412341234123412341234 - - - - - example.com. - - - - - 7654321 - - -`: ` - - - - - -date_updated -20160216T16:14:23 - - -date_delete -20170331T16:04:06 - - -is_premium -0 - - -date_hold_begin -20170215T02:04:06 - - -date_registry_end -20170215T02:04:06 - - -authinfo_expiration_date -20161211T21:31:20 - - -contacts - - -owner - - -handle -LEGO-GANDI - - -id -111111 - - - - -admin - - -handle -LEGO-GANDI - - -id -111111 - - - - -bill - - -handle -LEGO-GANDI - - -id -111111 - - - - -tech - - -handle -LEGO-GANDI - - -id -111111 - - - - -reseller - - - - -nameservers - -a.dns.gandi.net -b.dns.gandi.net -c.dns.gandi.net - - - -date_restore_end -20170501T02:04:06 - - -id -2222222 - - -authinfo -ABCDABCDAB - - -status - -clientTransferProhibited -serverTransferProhibited - - - -tags - - - - -date_hold_end -20170401T02:04:06 - - -services - -gandidns -gandimail - - - -date_pending_delete_end -20170506T02:04:06 - - -zone_id -7654321 - - -date_renew_begin -20120101T00:00:00 - - -fqdn -example.com - - -autorenew - - -date_registry_creation -20150215T02:04:06 - - -tld -org - - -date_created -20150215T03:04:06 - - - - - -`, - // CleanUp Request->Response 1 (setZone) - ` - - domain.zone.set - - - 123412341234123412341234 - - - - - example.com. - - - - - 1234567 - - -`: ` - - - - - -date_updated -20160216T16:24:38 - - -date_delete -20170331T16:04:06 - - -is_premium -0 - - -date_hold_begin -20170215T02:04:06 - - -date_registry_end -20170215T02:04:06 - - -authinfo_expiration_date -20161211T21:31:20 - - -contacts - - -owner - - -handle -LEGO-GANDI - - -id -111111 - - - - -admin - - -handle -LEGO-GANDI - - -id -111111 - - - - -bill - - -handle -LEGO-GANDI - - -id -111111 - - - - -tech - - -handle -LEGO-GANDI - - -id -111111 - - - - -reseller - - - - -nameservers - -a.dns.gandi.net -b.dns.gandi.net -c.dns.gandi.net - - - -date_restore_end -20170501T02:04:06 - - -id -2222222 - - -authinfo -ABCDABCDAB - - -status - -clientTransferProhibited -serverTransferProhibited - - - -tags - - - - -date_hold_end -20170401T02:04:06 - - -services - -gandidns -gandimail - - - -date_pending_delete_end -20170506T02:04:06 - - -zone_id -1234567 - - -date_renew_begin -20120101T00:00:00 - - -fqdn -example.com - - -autorenew - - -date_registry_creation -20150215T02:04:06 - - -tld -org - - -date_created -20150215T03:04:06 - - - - - -`, - // CleanUp Request->Response 2 (deleteZone) - ` - - domain.zone.delete - - - 123412341234123412341234 - - - - - 7654321 - - -`: ` - - - -1 - - - -`, -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go deleted file mode 100644 index 4112f6628..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go +++ /dev/null @@ -1,155 +0,0 @@ -// 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"` -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go deleted file mode 100644 index de84d827e..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package godaddy - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - godaddyAPIKey string - godaddyAPISecret string - godaddyDomain string - godaddyLiveTest bool -) - -func init() { - godaddyAPIKey = os.Getenv("GODADDY_API_KEY") - godaddyAPISecret = os.Getenv("GODADDY_API_SECRET") - godaddyDomain = os.Getenv("GODADDY_DOMAIN") - - if len(godaddyAPIKey) > 0 && len(godaddyAPISecret) > 0 && len(godaddyDomain) > 0 { - godaddyLiveTest = true - } -} - -func TestNewDNSProvider(t *testing.T) { - provider, err := NewDNSProvider() - - if !godaddyLiveTest { - assert.Error(t, err) - } else { - assert.NotNil(t, provider) - assert.NoError(t, err) - } -} - -func TestDNSProvider_Present(t *testing.T) { - if !godaddyLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(godaddyDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestDNSProvider_CleanUp(t *testing.T) { - if !godaddyLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(godaddyDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud.go b/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud.go deleted file mode 100644 index ba753f6dc..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud.go +++ /dev/null @@ -1,205 +0,0 @@ -// Package googlecloud implements a DNS provider for solving the DNS-01 -// challenge using Google Cloud DNS. -package googlecloud - -import ( - "fmt" - "io/ioutil" - "os" - "time" - - "github.com/xenolf/lego/acme" - - "golang.org/x/net/context" - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" - - "google.golang.org/api/dns/v1" -) - -// DNSProvider is an implementation of the DNSProvider interface. -type DNSProvider struct { - project string - client *dns.Service -} - -// NewDNSProvider returns a DNSProvider instance configured for Google Cloud -// DNS. Project name must be passed in the environment variable: GCE_PROJECT. -// A Service Account file can be passed in the environment variable: -// GCE_SERVICE_ACCOUNT_FILE -func NewDNSProvider() (*DNSProvider, error) { - project := os.Getenv("GCE_PROJECT") - if saFile, ok := os.LookupEnv("GCE_SERVICE_ACCOUNT_FILE"); ok { - return NewDNSProviderServiceAccount(project, saFile) - } - return NewDNSProviderCredentials(project) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Google Cloud DNS. -func NewDNSProviderCredentials(project string) (*DNSProvider, error) { - if project == "" { - return nil, fmt.Errorf("Google Cloud project name missing") - } - - client, err := google.DefaultClient(context.Background(), dns.NdevClouddnsReadwriteScope) - if err != nil { - return nil, fmt.Errorf("Unable to get Google Cloud client: %v", err) - } - svc, err := dns.New(client) - if err != nil { - return nil, fmt.Errorf("Unable to create Google Cloud DNS service: %v", err) - } - return &DNSProvider{ - project: project, - client: svc, - }, nil -} - -// NewDNSProviderServiceAccount uses the supplied service account JSON file to -// return a DNSProvider instance configured for Google Cloud DNS. -func NewDNSProviderServiceAccount(project string, saFile string) (*DNSProvider, error) { - if project == "" { - return nil, fmt.Errorf("Google Cloud project name missing") - } - if saFile == "" { - return nil, fmt.Errorf("Google Cloud Service Account file missing") - } - - dat, err := ioutil.ReadFile(saFile) - if err != nil { - return nil, fmt.Errorf("Unable to read Service Account file: %v", err) - } - conf, err := google.JWTConfigFromJSON(dat, dns.NdevClouddnsReadwriteScope) - if err != nil { - return nil, fmt.Errorf("Unable to acquire config: %v", err) - } - client := conf.Client(oauth2.NoContext) - - svc, err := dns.New(client) - if err != nil { - return nil, fmt.Errorf("Unable to create Google Cloud DNS service: %v", err) - } - return &DNSProvider{ - project: project, - client: svc, - }, nil -} - -// 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) - - zone, err := c.getHostedZone(domain) - if err != nil { - return err - } - - rec := &dns.ResourceRecordSet{ - Name: fqdn, - Rrdatas: []string{value}, - Ttl: int64(ttl), - Type: "TXT", - } - change := &dns.Change{ - Additions: []*dns.ResourceRecordSet{rec}, - } - - // Look for existing records. - list, err := c.client.ResourceRecordSets.List(c.project, zone).Name(fqdn).Type("TXT").Do() - if err != nil { - return err - } - if len(list.Rrsets) > 0 { - // Attempt to delete the existing records when adding our new one. - change.Deletions = list.Rrsets - } - - chg, err := c.client.Changes.Create(c.project, zone, change).Do() - if err != nil { - return err - } - - // wait for change to be acknowledged - for chg.Status == "pending" { - time.Sleep(time.Second) - - chg, err = c.client.Changes.Get(c.project, zone, chg.Id).Do() - if err != nil { - return err - } - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - zone, err := c.getHostedZone(domain) - if err != nil { - return err - } - - records, err := c.findTxtRecords(zone, fqdn) - if err != nil { - return err - } - - for _, rec := range records { - change := &dns.Change{ - Deletions: []*dns.ResourceRecordSet{rec}, - } - _, err = c.client.Changes.Create(c.project, zone, change).Do() - if err != nil { - return err - } - } - return nil -} - -// Timeout customizes the timeout values used by the ACME package for checking -// DNS record validity. -func (c *DNSProvider) Timeout() (timeout, interval time.Duration) { - return 180 * time.Second, 5 * time.Second -} - -// getHostedZone returns the managed-zone -func (c *DNSProvider) getHostedZone(domain string) (string, error) { - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return "", err - } - - zones, err := c.client.ManagedZones. - List(c.project). - DnsName(authZone). - Do() - if err != nil { - return "", fmt.Errorf("GoogleCloud API call failed: %v", err) - } - - if len(zones.ManagedZones) == 0 { - return "", fmt.Errorf("No matching GoogleCloud domain found for domain %s", authZone) - } - - return zones.ManagedZones[0].Name, nil -} - -func (c *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) { - - recs, err := c.client.ResourceRecordSets.List(c.project, zone).Do() - if err != nil { - return nil, err - } - - found := []*dns.ResourceRecordSet{} - for _, r := range recs.Rrsets { - if r.Type == "TXT" && r.Name == fqdn { - found = append(found, r) - } - } - - return found, nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud_test.go b/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud_test.go deleted file mode 100644 index 75a10d9a4..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/googlecloud/googlecloud_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package googlecloud - -import ( - "os" - "testing" - "time" - - "golang.org/x/net/context" - "golang.org/x/oauth2/google" - "google.golang.org/api/dns/v1" - - "github.com/stretchr/testify/assert" -) - -var ( - gcloudLiveTest bool - gcloudProject string - gcloudDomain string -) - -func init() { - gcloudProject = os.Getenv("GCE_PROJECT") - gcloudDomain = os.Getenv("GCE_DOMAIN") - _, err := google.DefaultClient(context.Background(), dns.NdevClouddnsReadwriteScope) - if err == nil && len(gcloudProject) > 0 && len(gcloudDomain) > 0 { - gcloudLiveTest = true - } -} - -func restoreGCloudEnv() { - os.Setenv("GCE_PROJECT", gcloudProject) -} - -func TestNewDNSProviderValid(t *testing.T) { - if !gcloudLiveTest { - t.Skip("skipping live test (requires credentials)") - } - os.Setenv("GCE_PROJECT", "") - _, err := NewDNSProviderCredentials("my-project") - assert.NoError(t, err) - restoreGCloudEnv() -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - if !gcloudLiveTest { - t.Skip("skipping live test (requires credentials)") - } - os.Setenv("GCE_PROJECT", "my-project") - _, err := NewDNSProvider() - assert.NoError(t, err) - restoreGCloudEnv() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("GCE_PROJECT", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "Google Cloud project name missing") - restoreGCloudEnv() -} - -func TestLiveGoogleCloudPresent(t *testing.T) { - if !gcloudLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(gcloudProject) - assert.NoError(t, err) - - err = provider.Present(gcloudDomain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveGoogleCloudPresentMultiple(t *testing.T) { - if !gcloudLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(gcloudProject) - assert.NoError(t, err) - - // Check that we're able to create multiple entries - err = provider.Present(gcloudDomain, "1", "123d==") - err = provider.Present(gcloudDomain, "2", "123d==") - assert.NoError(t, err) -} - -func TestLiveGoogleCloudCleanUp(t *testing.T) { - if !gcloudLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProviderCredentials(gcloudProject) - assert.NoError(t, err) - - err = provider.CleanUp(gcloudDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/linode/linode.go b/vendor/github.com/xenolf/lego/providers/dns/linode/linode.go deleted file mode 100644 index a91d2b489..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/linode/linode.go +++ /dev/null @@ -1,131 +0,0 @@ -// Package linode implements a DNS provider for solving the DNS-01 challenge -// using Linode DNS. -package linode - -import ( - "errors" - "os" - "strings" - "time" - - "github.com/timewasted/linode/dns" - "github.com/xenolf/lego/acme" -) - -const ( - dnsMinTTLSecs = 300 - dnsUpdateFreqMins = 15 - dnsUpdateFudgeSecs = 120 -) - -type hostedZoneInfo struct { - domainId int - resourceName string -} - -// DNSProvider implements the acme.ChallengeProvider interface. -type DNSProvider struct { - linode *dns.DNS -} - -// NewDNSProvider returns a DNSProvider instance configured for Linode. -// Credentials must be passed in the environment variable: LINODE_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - apiKey := os.Getenv("LINODE_API_KEY") - return NewDNSProviderCredentials(apiKey) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Linode. -func NewDNSProviderCredentials(apiKey string) (*DNSProvider, error) { - if len(apiKey) == 0 { - return nil, errors.New("Linode credentials missing") - } - - return &DNSProvider{ - linode: dns.New(apiKey), - }, nil -} - -// Timeout returns the timeout and interval to use when checking for DNS -// propagation. Adjusting here to cope with spikes in propagation times. -func (p *DNSProvider) Timeout() (timeout, interval time.Duration) { - // Since Linode only updates their zone files every X minutes, we need - // to figure out how many minutes we have to wait until we hit the next - // interval of X. We then wait another couple of minutes, just to be - // safe. Hopefully at some point during all of this, the record will - // have propagated throughout Linode's network. - minsRemaining := dnsUpdateFreqMins - (time.Now().Minute() % dnsUpdateFreqMins) - - timeout = (time.Duration(minsRemaining) * time.Minute) + - (dnsMinTTLSecs * time.Second) + - (dnsUpdateFudgeSecs * time.Second) - interval = 15 * time.Second - return -} - -// Present creates a TXT record using the specified parameters. -func (p *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zone, err := p.getHostedZoneInfo(fqdn) - if err != nil { - return err - } - - if _, err = p.linode.CreateDomainResourceTXT(zone.domainId, acme.UnFqdn(fqdn), value, 60); err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (p *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zone, err := p.getHostedZoneInfo(fqdn) - if err != nil { - return err - } - - // Get all TXT records for the specified domain. - resources, err := p.linode.GetResourcesByType(zone.domainId, "TXT") - if err != nil { - return err - } - - // Remove the specified resource, if it exists. - for _, resource := range resources { - if resource.Name == zone.resourceName && resource.Target == value { - resp, err := p.linode.DeleteDomainResource(resource.DomainID, resource.ResourceID) - if err != nil { - return err - } - if resp.ResourceID != resource.ResourceID { - return errors.New("Error deleting resource: resource IDs do not match!") - } - break - } - } - - return nil -} - -func (p *DNSProvider) getHostedZoneInfo(fqdn string) (*hostedZoneInfo, error) { - // Lookup the zone that handles the specified FQDN. - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return nil, err - } - resourceName := strings.TrimSuffix(fqdn, "."+authZone) - - // Query the authority zone. - domain, err := p.linode.GetDomain(acme.UnFqdn(authZone)) - if err != nil { - return nil, err - } - - return &hostedZoneInfo{ - domainId: domain.DomainID, - resourceName: resourceName, - }, nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/linode/linode_test.go b/vendor/github.com/xenolf/lego/providers/dns/linode/linode_test.go deleted file mode 100644 index d9713a275..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/linode/linode_test.go +++ /dev/null @@ -1,317 +0,0 @@ -package linode - -import ( - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/timewasted/linode" - "github.com/timewasted/linode/dns" -) - -type ( - LinodeResponse struct { - Action string `json:"ACTION"` - Data interface{} `json:"DATA"` - Errors []linode.ResponseError `json:"ERRORARRAY"` - } - MockResponse struct { - Response interface{} - Errors []linode.ResponseError - } - MockResponseMap map[string]MockResponse -) - -var ( - apiKey string - isTestLive bool -) - -func init() { - apiKey = os.Getenv("LINODE_API_KEY") - isTestLive = len(apiKey) != 0 -} - -func restoreEnv() { - os.Setenv("LINODE_API_KEY", apiKey) -} - -func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Ensure that we support the requested action. - action := r.URL.Query().Get("api_action") - resp, ok := responses[action] - if !ok { - msg := fmt.Sprintf("Unsupported mock action: %s", action) - require.FailNow(t, msg) - } - - // Build the response that the server will return. - linodeResponse := LinodeResponse{ - Action: action, - Data: resp.Response, - Errors: resp.Errors, - } - rawResponse, err := json.Marshal(linodeResponse) - if err != nil { - msg := fmt.Sprintf("Failed to JSON encode response: %v", err) - require.FailNow(t, msg) - } - - // Send the response. - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(rawResponse) - })) - - time.Sleep(100 * time.Millisecond) - return srv -} - -func TestNewDNSProviderWithEnv(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - _, err := NewDNSProvider() - assert.NoError(t, err) -} - -func TestNewDNSProviderWithoutEnv(t *testing.T) { - os.Setenv("LINODE_API_KEY", "") - defer restoreEnv() - _, err := NewDNSProvider() - assert.EqualError(t, err, "Linode credentials missing") -} - -func TestNewDNSProviderCredentialsWithKey(t *testing.T) { - _, err := NewDNSProviderCredentials("testing") - assert.NoError(t, err) -} - -func TestNewDNSProviderCredentialsWithoutKey(t *testing.T) { - _, err := NewDNSProviderCredentials("") - assert.EqualError(t, err, "Linode credentials missing") -} - -func TestDNSProvider_Present(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: domain, - DomainID: 1234, - }, - }, - }, - "domain.resource.create": MockResponse{ - Response: dns.ResourceResponse{ - ResourceID: 1234, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.Present(domain, "", keyAuth) - assert.NoError(t, err) -} - -func TestDNSProvider_PresentNoDomain(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: "foobar.com", - DomainID: 1234, - }, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.Present(domain, "", keyAuth) - assert.EqualError(t, err, "dns: requested domain not found") -} - -func TestDNSProvider_PresentCreateFailed(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: domain, - DomainID: 1234, - }, - }, - }, - "domain.resource.create": MockResponse{ - Response: nil, - Errors: []linode.ResponseError{ - linode.ResponseError{ - Code: 1234, - Message: "Failed to create domain resource", - }, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.Present(domain, "", keyAuth) - assert.EqualError(t, err, "Failed to create domain resource") -} - -func TestDNSProvider_PresentLive(t *testing.T) { - if !isTestLive { - t.Skip("Skipping live test") - } -} - -func TestDNSProvider_CleanUp(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: domain, - DomainID: 1234, - }, - }, - }, - "domain.resource.list": MockResponse{ - Response: []dns.Resource{ - dns.Resource{ - DomainID: 1234, - Name: "_acme-challenge", - ResourceID: 1234, - Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM", - Type: "TXT", - }, - }, - }, - "domain.resource.delete": MockResponse{ - Response: dns.ResourceResponse{ - ResourceID: 1234, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.CleanUp(domain, "", keyAuth) - assert.NoError(t, err) -} - -func TestDNSProvider_CleanUpNoDomain(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: "foobar.com", - DomainID: 1234, - }, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.CleanUp(domain, "", keyAuth) - assert.EqualError(t, err, "dns: requested domain not found") -} - -func TestDNSProvider_CleanUpDeleteFailed(t *testing.T) { - os.Setenv("LINODE_API_KEY", "testing") - defer restoreEnv() - p, err := NewDNSProvider() - assert.NoError(t, err) - - domain := "example.com" - keyAuth := "dGVzdGluZw==" - mockResponses := MockResponseMap{ - "domain.list": MockResponse{ - Response: []dns.Domain{ - dns.Domain{ - Domain: domain, - DomainID: 1234, - }, - }, - }, - "domain.resource.list": MockResponse{ - Response: []dns.Resource{ - dns.Resource{ - DomainID: 1234, - Name: "_acme-challenge", - ResourceID: 1234, - Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM", - Type: "TXT", - }, - }, - }, - "domain.resource.delete": MockResponse{ - Response: nil, - Errors: []linode.ResponseError{ - linode.ResponseError{ - Code: 1234, - Message: "Failed to delete domain resource", - }, - }, - }, - } - mockSrv := newMockServer(t, mockResponses) - defer mockSrv.Close() - p.linode.ToLinode().SetEndpoint(mockSrv.URL) - - err = p.CleanUp(domain, "", keyAuth) - assert.EqualError(t, err, "Failed to delete domain resource") -} - -func TestDNSProvider_CleanUpLive(t *testing.T) { - if !isTestLive { - t.Skip("Skipping live test") - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go b/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go deleted file mode 100644 index d7eb40935..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go +++ /dev/null @@ -1,416 +0,0 @@ -// Package namecheap implements a DNS provider for solving the DNS-01 -// challenge using namecheap DNS. -package namecheap - -import ( - "encoding/xml" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "os" - "strings" - "time" - - "github.com/xenolf/lego/acme" -) - -// Notes about namecheap's tool API: -// 1. Using the API requires registration. Once registered, use your account -// name and API key to access the API. -// 2. There is no API to add or modify a single DNS record. Instead you must -// read the entire list of records, make modifications, and then write the -// entire updated list of records. (Yuck.) -// 3. Namecheap's DNS updates can be slow to propagate. I've seen them take -// as long as an hour. -// 4. Namecheap requires you to whitelist the IP address from which you call -// its APIs. It also requires all API calls to include the whitelisted IP -// address as a form or query string value. This code uses a namecheap -// service to query the client's IP address. - -var ( - debug = false - defaultBaseURL = "https://api.namecheap.com/xml.response" - getIPURL = "https://dynamicdns.park-your-domain.com/getip" - httpClient = http.Client{Timeout: 60 * time.Second} -) - -// DNSProvider is an implementation of the ChallengeProviderTimeout interface -// that uses Namecheap's tool API to manage TXT records for a domain. -type DNSProvider struct { - baseURL string - apiUser string - apiKey string - clientIP string -} - -// NewDNSProvider returns a DNSProvider instance configured for namecheap. -// Credentials must be passed in the environment variables: NAMECHEAP_API_USER -// and NAMECHEAP_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - apiUser := os.Getenv("NAMECHEAP_API_USER") - apiKey := os.Getenv("NAMECHEAP_API_KEY") - return NewDNSProviderCredentials(apiUser, apiKey) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for namecheap. -func NewDNSProviderCredentials(apiUser, apiKey string) (*DNSProvider, error) { - if apiUser == "" || apiKey == "" { - return nil, fmt.Errorf("Namecheap credentials missing") - } - - clientIP, err := getClientIP() - if err != nil { - return nil, err - } - - return &DNSProvider{ - baseURL: defaultBaseURL, - apiUser: apiUser, - apiKey: apiKey, - clientIP: clientIP, - }, nil -} - -// Timeout returns the timeout and interval to use when checking for DNS -// propagation. Namecheap can sometimes take a long time to complete an -// update, so wait up to 60 minutes for the update to propagate. -func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { - return 60 * time.Minute, 15 * time.Second -} - -// host describes a DNS record returned by the Namecheap DNS gethosts API. -// Namecheap uses the term "host" to refer to all DNS records that include -// a host field (A, AAAA, CNAME, NS, TXT, URL). -type host struct { - Type string `xml:",attr"` - Name string `xml:",attr"` - Address string `xml:",attr"` - MXPref string `xml:",attr"` - TTL string `xml:",attr"` -} - -// apierror describes an error record in a namecheap API response. -type apierror struct { - Number int `xml:",attr"` - Description string `xml:",innerxml"` -} - -// getClientIP returns the client's public IP address. It uses namecheap's -// IP discovery service to perform the lookup. -func getClientIP() (addr string, err error) { - resp, err := httpClient.Get(getIPURL) - if err != nil { - return "", err - } - defer resp.Body.Close() - - clientIP, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", err - } - - if debug { - fmt.Println("Client IP:", string(clientIP)) - } - return string(clientIP), nil -} - -// A challenge repesents all the data needed to specify a dns-01 challenge -// to lets-encrypt. -type challenge struct { - domain string - key string - keyFqdn string - keyValue string - tld string - sld string - host string -} - -// 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) { - domain = acme.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 { - return nil, fmt.Errorf("Invalid domain name '%s'", domain) - } - - tld := strings.Join(parts[longest:], ".") - sld := parts[longest-1] - - var host string - if longest >= 1 { - host = strings.Join(parts[:longest-1], ".") - } - - key, keyValue, _ := acme.DNS01Record(domain, keyAuth) - - return &challenge{ - domain: domain, - key: "_acme-challenge." + host, - keyFqdn: key, - keyValue: keyValue, - tld: tld, - sld: sld, - host: host, - }, nil -} - -// setGlobalParams adds the namecheap global parameters to the provided url -// Values record. -func (d *DNSProvider) setGlobalParams(v *url.Values, cmd string) { - v.Set("ApiUser", d.apiUser) - v.Set("ApiKey", d.apiKey) - v.Set("UserName", d.apiUser) - v.Set("ClientIp", d.clientIP) - v.Set("Command", cmd) -} - -// getTLDs requests the list of available TLDs from namecheap. -func (d *DNSProvider) getTLDs() (tlds map[string]string, err error) { - values := make(url.Values) - d.setGlobalParams(&values, "namecheap.domains.getTldList") - - reqURL, _ := url.Parse(d.baseURL) - reqURL.RawQuery = values.Encode() - - resp, err := httpClient.Get(reqURL.String()) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return nil, fmt.Errorf("getHosts HTTP error %d", resp.StatusCode) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - type GetTldsResponse struct { - XMLName xml.Name `xml:"ApiResponse"` - Errors []apierror `xml:"Errors>Error"` - Result []struct { - Name string `xml:",attr"` - } `xml:"CommandResponse>Tlds>Tld"` - } - - var gtr GetTldsResponse - if err := xml.Unmarshal(body, >r); err != nil { - return nil, err - } - if len(gtr.Errors) > 0 { - return nil, fmt.Errorf("Namecheap error: %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 using the Namecheap API. -func (d *DNSProvider) getHosts(ch *challenge) (hosts []host, err error) { - values := make(url.Values) - d.setGlobalParams(&values, "namecheap.domains.dns.getHosts") - values.Set("SLD", ch.sld) - values.Set("TLD", ch.tld) - - reqURL, _ := url.Parse(d.baseURL) - reqURL.RawQuery = values.Encode() - - resp, err := httpClient.Get(reqURL.String()) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return nil, fmt.Errorf("getHosts HTTP error %d", resp.StatusCode) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - type GetHostsResponse struct { - XMLName xml.Name `xml:"ApiResponse"` - Status string `xml:"Status,attr"` - Errors []apierror `xml:"Errors>Error"` - Hosts []host `xml:"CommandResponse>DomainDNSGetHostsResult>host"` - } - - var ghr GetHostsResponse - if err = xml.Unmarshal(body, &ghr); err != nil { - return nil, err - } - if len(ghr.Errors) > 0 { - return nil, fmt.Errorf("Namecheap error: %s [%d]", - ghr.Errors[0].Description, ghr.Errors[0].Number) - } - - return ghr.Hosts, nil -} - -// setHosts writes the full list of DNS host records using the Namecheap API. -func (d *DNSProvider) setHosts(ch *challenge, hosts []host) error { - values := make(url.Values) - d.setGlobalParams(&values, "namecheap.domains.dns.setHosts") - values.Set("SLD", ch.sld) - values.Set("TLD", ch.tld) - - for i, h := range hosts { - ind := fmt.Sprintf("%d", i+1) - values.Add("HostName"+ind, h.Name) - values.Add("RecordType"+ind, h.Type) - values.Add("Address"+ind, h.Address) - values.Add("MXPref"+ind, h.MXPref) - values.Add("TTL"+ind, h.TTL) - } - - resp, err := httpClient.PostForm(d.baseURL, values) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return fmt.Errorf("setHosts HTTP error %d", resp.StatusCode) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - type SetHostsResponse struct { - XMLName xml.Name `xml:"ApiResponse"` - Status string `xml:"Status,attr"` - Errors []apierror `xml:"Errors>Error"` - Result struct { - IsSuccess string `xml:",attr"` - } `xml:"CommandResponse>DomainDNSSetHostsResult"` - } - - var shr SetHostsResponse - if err := xml.Unmarshal(body, &shr); err != nil { - return err - } - if len(shr.Errors) > 0 { - return fmt.Errorf("Namecheap error: %s [%d]", - shr.Errors[0].Description, shr.Errors[0].Number) - } - if shr.Result.IsSuccess != "true" { - return fmt.Errorf("Namecheap setHosts failed.") - } - - return nil -} - -// addChallengeRecord adds a DNS challenge TXT record to a list of namecheap -// host records. -func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]host) { - host := host{ - Name: ch.key, - Type: "TXT", - Address: ch.keyValue, - MXPref: "10", - TTL: "120", - } - - // If there's already a TXT record with the same name, replace it. - for i, h := range *hosts { - if h.Name == ch.key && h.Type == "TXT" { - (*hosts)[i] = host - return - } - } - - // No record was replaced, so add a new one. - *hosts = append(*hosts, host) -} - -// removeChallengeRecord removes a DNS challenge TXT record from a list of -// namecheap host records. Return true if a record was removed. -func (d *DNSProvider) removeChallengeRecord(ch *challenge, hosts *[]host) bool { - // Find the challenge TXT record and remove it if found. - for i, h := range *hosts { - if h.Name == ch.key && h.Type == "TXT" { - *hosts = append((*hosts)[:i], (*hosts)[i+1:]...) - return true - } - } - - return false -} - -// 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 err - } - - ch, err := newChallenge(domain, keyAuth, tlds) - if err != nil { - return err - } - - hosts, err := d.getHosts(ch) - if err != nil { - return err - } - - d.addChallengeRecord(ch, &hosts) - - if debug { - for _, h := range hosts { - fmt.Printf( - "%-5.5s %-30.30s %-6s %-70.70s\n", - h.Type, h.Name, h.TTL, h.Address) - } - } - - return d.setHosts(ch, hosts) -} - -// 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 err - } - - ch, err := newChallenge(domain, keyAuth, tlds) - if err != nil { - return err - } - - hosts, err := d.getHosts(ch) - if err != nil { - return err - } - - if removed := d.removeChallengeRecord(ch, &hosts); !removed { - return nil - } - - return d.setHosts(ch, hosts) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap_test.go b/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap_test.go deleted file mode 100644 index 0631d4a3e..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap_test.go +++ /dev/null @@ -1,402 +0,0 @@ -package namecheap - -import ( - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "testing" -) - -var ( - fakeUser = "foo" - fakeKey = "bar" - fakeClientIP = "10.0.0.1" - - tlds = 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 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, "", tlds) - - assertEq(t, "ApiUser", values.Get("ApiUser"), fakeUser) - assertEq(t, "ApiKey", values.Get("ApiKey"), fakeKey) - assertEq(t, "UserName", values.Get("UserName"), fakeUser) - assertEq(t, "ClientIp", values.Get("ClientIp"), fakeClientIP) - assertEq(t, "SLD", values.Get("SLD"), ch.sld) - assertEq(t, "TLD", values.Get("TLD"), ch.tld) -} - -func mockServer(tc *testcase, t *testing.T, w http.ResponseWriter, r *http.Request) { - switch r.Method { - - case "GET": - values := r.URL.Query() - cmd := values.Get("Command") - switch cmd { - case "namecheap.domains.dns.getHosts": - assertHdr(tc, t, &values) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, tc.getHostsResponse) - case "namecheap.domains.getTldList": - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, responseGetTlds) - default: - t.Errorf("Unexpected GET command: %s", cmd) - } - - case "POST": - r.ParseForm() - values := r.Form - cmd := values.Get("Command") - switch cmd { - case "namecheap.domains.dns.setHosts": - assertHdr(tc, t, &values) - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, tc.setHostsResponse) - default: - t.Errorf("Unexpected POST command: %s", cmd) - } - - default: - t.Errorf("Unexpected http method: %s", r.Method) - - } -} - -func testGetHosts(tc *testcase, t *testing.T) { - mock := httptest.NewServer(http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - mockServer(tc, t, w, r) - })) - defer mock.Close() - - prov := &DNSProvider{ - baseURL: mock.URL, - apiUser: fakeUser, - apiKey: fakeKey, - clientIP: fakeClientIP, - } - - ch, _ := newChallenge(tc.domain, "", tlds) - hosts, err := prov.getHosts(ch) - if tc.errString != "" { - if err == nil || err.Error() != tc.errString { - t.Errorf("Namecheap getHosts case %s expected error", tc.name) - } - } else { - if err != nil { - t.Errorf("Namecheap getHosts case %s failed\n%v", tc.name, err) - } - } - -next1: - for _, h := range hosts { - for _, th := range tc.hosts { - if h == th { - continue next1 - } - } - t.Errorf("getHosts case %s unexpected record [%s:%s:%s]", - tc.name, h.Type, h.Name, h.Address) - } - -next2: - for _, th := range tc.hosts { - for _, h := range hosts { - if h == th { - continue next2 - } - } - t.Errorf("getHosts case %s missing record [%s:%s:%s]", - tc.name, th.Type, th.Name, th.Address) - } -} - -func mockDNSProvider(url string) *DNSProvider { - return &DNSProvider{ - baseURL: url, - apiUser: fakeUser, - apiKey: fakeKey, - clientIP: fakeClientIP, - } -} - -func testSetHosts(tc *testcase, t *testing.T) { - mock := httptest.NewServer(http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - mockServer(tc, t, w, r) - })) - defer mock.Close() - - prov := mockDNSProvider(mock.URL) - ch, _ := newChallenge(tc.domain, "", tlds) - hosts, err := prov.getHosts(ch) - if tc.errString != "" { - if err == nil || err.Error() != tc.errString { - t.Errorf("Namecheap getHosts case %s expected error", tc.name) - } - } else { - if err != nil { - t.Errorf("Namecheap getHosts case %s failed\n%v", tc.name, err) - } - } - if err != nil { - return - } - - err = prov.setHosts(ch, hosts) - if err != nil { - t.Errorf("Namecheap setHosts case %s failed", tc.name) - } -} - -func testPresent(tc *testcase, t *testing.T) { - mock := httptest.NewServer(http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - mockServer(tc, t, w, r) - })) - defer mock.Close() - - prov := mockDNSProvider(mock.URL) - err := prov.Present(tc.domain, "", "dummyKey") - if tc.errString != "" { - if err == nil || err.Error() != tc.errString { - t.Errorf("Namecheap Present case %s expected error", tc.name) - } - } else { - if err != nil { - t.Errorf("Namecheap Present case %s failed\n%v", tc.name, err) - } - } -} - -func testCleanUp(tc *testcase, t *testing.T) { - mock := httptest.NewServer(http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - mockServer(tc, t, w, r) - })) - defer mock.Close() - - prov := mockDNSProvider(mock.URL) - err := prov.CleanUp(tc.domain, "", "dummyKey") - if tc.errString != "" { - if err == nil || err.Error() != tc.errString { - t.Errorf("Namecheap CleanUp case %s expected error", tc.name) - } - } else { - if err != nil { - t.Errorf("Namecheap CleanUp case %s failed\n%v", tc.name, err) - } - } -} - -func TestNamecheap(t *testing.T) { - for _, tc := range testcases { - testGetHosts(&tc, t) - testSetHosts(&tc, t) - testPresent(&tc, t) - testCleanUp(&tc, t) - } -} - -func TestNamecheapDomainSplit(t *testing.T) { - tests := []struct { - domain string - valid bool - tld string - sld string - host string - }{ - {"a.b.c.test.co.uk", true, "co.uk", "test", "a.b.c"}, - {"test.co.uk", true, "co.uk", "test", ""}, - {"test.com", true, "com", "test", ""}, - {"test.co.com", true, "co.com", "test", ""}, - {"www.test.com.au", true, "com.au", "test", "www"}, - {"www.za.com", true, "za.com", "www", ""}, - {"", false, "", "", ""}, - {"a", false, "", "", ""}, - {"com", false, "", "", ""}, - {"co.com", false, "", "", ""}, - {"co.uk", false, "", "", ""}, - {"test.au", false, "", "", ""}, - {"za.com", false, "", "", ""}, - {"www.za", false, "", "", ""}, - {"www.test.au", false, "", "", ""}, - {"www.test.unk", false, "", "", ""}, - } - - for _, test := range tests { - valid := true - ch, err := newChallenge(test.domain, "", tlds) - if err != nil { - valid = false - } - - if test.valid && !valid { - t.Errorf("Expected '%s' to split", test.domain) - } else if !test.valid && valid { - t.Errorf("Expected '%s' to produce error", test.domain) - } - - 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) - } - } -} - -type testcase struct { - name string - domain string - hosts []host - errString string - getHostsResponse string - setHostsResponse string -} - -var testcases = []testcase{ - { - "Test:Success:1", - "test.example.com", - []host{ - {"A", "home", "10.0.0.1", "10", "1799"}, - {"A", "www", "10.0.0.2", "10", "1200"}, - {"AAAA", "a", "::0", "10", "1799"}, - {"CNAME", "*", "example.com.", "10", "1799"}, - {"MXE", "example.com", "10.0.0.5", "10", "1800"}, - {"URL", "xyz", "https://google.com", "10", "1799"}, - }, - "", - responseGetHostsSuccess1, - responseSetHostsSuccess1, - }, - { - "Test:Success:2", - "example.com", - []host{ - {"A", "@", "10.0.0.2", "10", "1200"}, - {"A", "www", "10.0.0.3", "10", "60"}, - }, - "", - responseGetHostsSuccess2, - responseSetHostsSuccess2, - }, - { - "Test:Error:BadApiKey:1", - "test.example.com", - nil, - "Namecheap error: API Key is invalid or API access has not been enabled [1011102]", - responseGetHostsErrorBadAPIKey1, - "", - }, -} - -var responseGetHostsSuccess1 = ` - - - - namecheap.domains.dns.getHosts - - - - - - - - - - - PHX01SBAPI01 - --5:00 - 3.338 -` - -var responseSetHostsSuccess1 = ` - - - - namecheap.domains.dns.setHosts - - - - - - PHX01SBAPI01 - --5:00 - 2.347 -` - -var responseGetHostsSuccess2 = ` - - - - namecheap.domains.dns.getHosts - - - - - - - PHX01SBAPI01 - --5:00 - 3.338 -` - -var responseSetHostsSuccess2 = ` - - - - namecheap.domains.dns.setHosts - - - - - - PHX01SBAPI01 - --5:00 - 2.347 -` - -var responseGetHostsErrorBadAPIKey1 = ` - - - API Key is invalid or API access has not been enabled - - - - PHX01SBAPI01 - --5:00 - 0 -` - -var responseGetTlds = ` - - - - namecheap.domains.getTldList - - - Most recognized top level domain - - - PHX01SBAPI01 - --5:00 - 0.004 -` diff --git a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go b/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go deleted file mode 100644 index 105d73f89..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go +++ /dev/null @@ -1,97 +0,0 @@ -// Package ns1 implements a DNS provider for solving the DNS-01 challenge -// using NS1 DNS. -package ns1 - -import ( - "fmt" - "net/http" - "os" - "time" - - "github.com/xenolf/lego/acme" - "gopkg.in/ns1/ns1-go.v2/rest" - "gopkg.in/ns1/ns1-go.v2/rest/model/dns" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface. -type DNSProvider struct { - client *rest.Client -} - -// NewDNSProvider returns a DNSProvider instance configured for NS1. -// Credentials must be passed in the environment variables: NS1_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - key := os.Getenv("NS1_API_KEY") - if key == "" { - return nil, fmt.Errorf("NS1 credentials missing") - } - return NewDNSProviderCredentials(key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for NS1. -func NewDNSProviderCredentials(key string) (*DNSProvider, error) { - if key == "" { - return nil, fmt.Errorf("NS1 credentials missing") - } - - httpClient := &http.Client{Timeout: time.Second * 10} - client := rest.NewClient(httpClient, rest.SetAPIKey(key)) - - return &DNSProvider{client}, nil -} - -// 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) - - zone, err := c.getHostedZone(domain) - if err != nil { - return err - } - - record := c.newTxtRecord(zone, fqdn, value, ttl) - _, err = c.client.Records.Create(record) - if err != nil && err != rest.ErrRecordExists { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - zone, err := c.getHostedZone(domain) - if err != nil { - return err - } - - name := acme.UnFqdn(fqdn) - _, err = c.client.Records.Delete(zone.Zone, name, "TXT") - return err -} - -func (c *DNSProvider) getHostedZone(domain string) (*dns.Zone, error) { - zone, _, err := c.client.Zones.Get(domain) - if err != nil { - return nil, err - } - - return zone, nil -} - -func (c *DNSProvider) newTxtRecord(zone *dns.Zone, fqdn, value string, ttl int) *dns.Record { - name := acme.UnFqdn(fqdn) - - return &dns.Record{ - Type: "TXT", - Zone: zone.Zone, - Domain: name, - TTL: ttl, - Answers: []*dns.Answer{ - {Rdata: []string{value}}, - }, - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1_test.go b/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1_test.go deleted file mode 100644 index eb9150dde..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package ns1 - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - liveTest bool - apiKey string - domain string -) - -func init() { - apiKey = os.Getenv("NS1_API_KEY") - domain = os.Getenv("NS1_DOMAIN") - if len(apiKey) > 0 && len(domain) > 0 { - liveTest = true - } -} - -func restoreNS1Env() { - os.Setenv("NS1_API_KEY", apiKey) -} - -func TestNewDNSProviderValid(t *testing.T) { - os.Setenv("NS1_API_KEY", "") - _, err := NewDNSProviderCredentials("123") - assert.NoError(t, err) - restoreNS1Env() -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("NS1_API_KEY", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "NS1 credentials missing") - restoreNS1Env() -} - -func TestLivePresent(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(apiKey) - assert.NoError(t, err) - - err = provider.Present(domain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveCleanUp(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProviderCredentials(apiKey) - assert.NoError(t, err) - - err = provider.CleanUp(domain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/otc/mock.go b/vendor/github.com/xenolf/lego/providers/dns/otc/mock.go deleted file mode 100644 index 0f2acb4b4..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/otc/mock.go +++ /dev/null @@ -1,152 +0,0 @@ -package otc - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" -) - -var fakeOTCUserName = "test" -var fakeOTCPassword = "test" -var fakeOTCDomainName = "test" -var fakeOTCProjectName = "test" -var fakeOTCToken = "62244bc21da68d03ebac94e6636ff01f" - -type DNSMock struct { - t *testing.T - Server *httptest.Server - Mux *http.ServeMux -} - -func NewDNSMock(t *testing.T) *DNSMock { - return &DNSMock{ - t: t, - } -} - -// Setup creates the mock server -func (m *DNSMock) Setup() { - m.Mux = http.NewServeMux() - m.Server = httptest.NewServer(m.Mux) -} - -// ShutdownServer creates the mock server -func (m *DNSMock) ShutdownServer() { - m.Server.Close() -} - -func (m *DNSMock) HandleAuthSuccessfully() { - m.Mux.HandleFunc("/v3/auth/token", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Subject-Token", fakeOTCToken) - - fmt.Fprintf(w, `{ - "token": { - "catalog": [ - { - "type": "dns", - "id": "56cd81db1f8445d98652479afe07c5ba", - "name": "", - "endpoints": [ - { - "url": "%s", - "region": "eu-de", - "region_id": "eu-de", - "interface": "public", - "id": "0047a06690484d86afe04877074efddf" - } - ] - } - ] - }}`, m.Server.URL) - }) -} - -func (m *DNSMock) HandleListZonesSuccessfully() { - m.Mux.HandleFunc("/v2/zones", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{ - "zones":[{ - "id":"123123" - }]} - `) - - assert.Equal(m.t, r.Method, "GET") - assert.Equal(m.t, r.URL.Path, "/v2/zones") - assert.Equal(m.t, r.URL.RawQuery, "name=example.com.") - assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json") - }) -} - -func (m *DNSMock) HandleListZonesEmpty() { - m.Mux.HandleFunc("/v2/zones", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{ - "zones":[ - ]} - `) - - assert.Equal(m.t, r.Method, "GET") - assert.Equal(m.t, r.URL.Path, "/v2/zones") - assert.Equal(m.t, r.URL.RawQuery, "name=example.com.") - assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json") - }) -} - -func (m *DNSMock) HandleDeleteRecordsetsSuccessfully() { - m.Mux.HandleFunc("/v2/zones/123123/recordsets/321321", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{ - "zones":[{ - "id":"123123" - }]} - `) - - assert.Equal(m.t, r.Method, "DELETE") - assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets/321321") - assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json") - }) -} - -func (m *DNSMock) HandleListRecordsetsEmpty() { - m.Mux.HandleFunc("/v2/zones/123123/recordsets", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{ - "recordsets":[ - ]} - `) - - assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets") - assert.Equal(m.t, r.URL.RawQuery, "type=TXT&name=_acme-challenge.example.com.") - }) -} -func (m *DNSMock) HandleListRecordsetsSuccessfully() { - m.Mux.HandleFunc("/v2/zones/123123/recordsets", func(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" { - fmt.Fprintf(w, `{ - "recordsets":[{ - "id":"321321" - }]} - `) - - assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets") - assert.Equal(m.t, r.URL.RawQuery, "type=TXT&name=_acme-challenge.example.com.") - - } else if r.Method == "POST" { - body, err := ioutil.ReadAll(r.Body) - - assert.Nil(m.t, err) - exceptedString := "{\"name\":\"_acme-challenge.example.com.\",\"description\":\"Added TXT record for ACME dns-01 challenge using lego client\",\"type\":\"TXT\",\"ttl\":300,\"records\":[\"\\\"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI\\\"\"]}" - assert.Equal(m.t, string(body), exceptedString) - - fmt.Fprintf(w, `{ - "recordsets":[{ - "id":"321321" - }]} - `) - - } else { - m.t.Errorf("Expected method to be 'GET' or 'POST' but got '%s'", r.Method) - } - - assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json") - }) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/otc/otc.go b/vendor/github.com/xenolf/lego/providers/dns/otc/otc.go deleted file mode 100644 index 86bcaa9b7..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/otc/otc.go +++ /dev/null @@ -1,388 +0,0 @@ -// Package otc implements a DNS provider for solving the DNS-01 challenge -// using Open Telekom Cloud Managed DNS. -package otc - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "time" - - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface that uses -// OTC's Managed DNS API to manage TXT records for a domain. -type DNSProvider struct { - identityEndpoint string - otcBaseURL string - domainName string - projectName string - userName string - password string - token string -} - -// NewDNSProvider returns a DNSProvider instance configured for OTC DNS. -// Credentials must be passed in the environment variables: OTC_USER_NAME, -// OTC_DOMAIN_NAME, OTC_PASSWORD OTC_PROJECT_NAME and OTC_IDENTITY_ENDPOINT. -func NewDNSProvider() (*DNSProvider, error) { - domainName := os.Getenv("OTC_DOMAIN_NAME") - userName := os.Getenv("OTC_USER_NAME") - password := os.Getenv("OTC_PASSWORD") - projectName := os.Getenv("OTC_PROJECT_NAME") - identityEndpoint := os.Getenv("OTC_IDENTITY_ENDPOINT") - return NewDNSProviderCredentials(domainName, userName, password, projectName, identityEndpoint) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for OTC DNS. -func NewDNSProviderCredentials(domainName, userName, password, projectName, identityEndpoint string) (*DNSProvider, error) { - if domainName == "" || userName == "" || password == "" || projectName == "" { - return nil, fmt.Errorf("OTC credentials missing") - } - - if identityEndpoint == "" { - identityEndpoint = "https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens" - } - - return &DNSProvider{ - identityEndpoint: identityEndpoint, - domainName: domainName, - userName: userName, - password: password, - projectName: projectName, - }, nil -} - -func (d *DNSProvider) SendRequest(method, resource string, payload interface{}) (io.Reader, error) { - url := fmt.Sprintf("%s/%s", d.otcBaseURL, resource) - - body, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(method, url, bytes.NewReader(body)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - if len(d.token) > 0 { - req.Header.Set("X-Auth-Token", d.token) - } - - // Workaround for keep alive bug in otc api - tr := http.DefaultTransport.(*http.Transport) - tr.DisableKeepAlives = true - - client := &http.Client{ - Timeout: time.Duration(10 * time.Second), - Transport: tr, - } - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return nil, fmt.Errorf("OTC API request %s failed with HTTP status code %d", url, resp.StatusCode) - } - - body1, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - return bytes.NewReader(body1), nil -} - -func (d *DNSProvider) loginRequest() error { - type nameResponse struct { - Name string `json:"name"` - } - - type userResponse struct { - Name string `json:"name"` - Password string `json:"password"` - Domain nameResponse `json:"domain"` - } - - type passwordResponse struct { - User userResponse `json:"user"` - } - type identityResponse struct { - Methods []string `json:"methods"` - Password passwordResponse `json:"password"` - } - - type scopeResponse struct { - Project nameResponse `json:"project"` - } - - type authResponse struct { - Identity identityResponse `json:"identity"` - Scope scopeResponse `json:"scope"` - } - - type loginResponse struct { - Auth authResponse `json:"auth"` - } - - userResp := userResponse{ - Name: d.userName, - Password: d.password, - Domain: nameResponse{ - Name: d.domainName, - }, - } - - loginResp := loginResponse{ - Auth: authResponse{ - Identity: identityResponse{ - Methods: []string{"password"}, - Password: passwordResponse{ - User: userResp, - }, - }, - Scope: scopeResponse{ - Project: nameResponse{ - Name: d.projectName, - }, - }, - }, - } - - body, err := json.Marshal(loginResp) - if err != nil { - return err - } - req, err := http.NewRequest("POST", d.identityEndpoint, bytes.NewReader(body)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{Timeout: time.Duration(10 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return fmt.Errorf("OTC API request failed with HTTP status code %d", resp.StatusCode) - } - - d.token = resp.Header.Get("X-Subject-Token") - - if d.token == "" { - return fmt.Errorf("unable to get auth token") - } - - type endpointResponse struct { - Token struct { - Catalog []struct { - Type string `json:"type"` - Endpoints []struct { - URL string `json:"url"` - } `json:"endpoints"` - } `json:"catalog"` - } `json:"token"` - } - var endpointResp endpointResponse - - err = json.NewDecoder(resp.Body).Decode(&endpointResp) - if err != nil { - return err - } - - for _, v := range endpointResp.Token.Catalog { - if v.Type == "dns" { - for _, endpoint := range v.Endpoints { - d.otcBaseURL = fmt.Sprintf("%s/v2", endpoint.URL) - continue - } - } - } - - if d.otcBaseURL == "" { - return fmt.Errorf("unable to get dns endpoint") - } - - return nil -} - -// Starts a new OTC API Session. Authenticates using userName, password -// and receives a token to be used in for subsequent requests. -func (d *DNSProvider) login() error { - err := d.loginRequest() - if err != nil { - return err - } - - return nil -} - -func (d *DNSProvider) getZoneID(zone string) (string, error) { - type zoneItem struct { - ID string `json:"id"` - } - - type zonesResponse struct { - Zones []zoneItem `json:"zones"` - } - - resource := fmt.Sprintf("zones?name=%s", zone) - resp, err := d.SendRequest("GET", resource, nil) - if err != nil { - return "", err - } - - var zonesRes zonesResponse - err = json.NewDecoder(resp).Decode(&zonesRes) - if err != nil { - return "", err - } - - if len(zonesRes.Zones) < 1 { - return "", fmt.Errorf("zone %s not found", zone) - } - - if len(zonesRes.Zones) > 1 { - return "", fmt.Errorf("to many zones found") - } - - if zonesRes.Zones[0].ID == "" { - return "", fmt.Errorf("id not found") - } - - return zonesRes.Zones[0].ID, nil -} - -func (d *DNSProvider) getRecordSetID(zoneID string, fqdn string) (string, error) { - type recordSet struct { - ID string `json:"id"` - } - - type recordSetsResponse struct { - RecordSets []recordSet `json:"recordsets"` - } - - resource := fmt.Sprintf("zones/%s/recordsets?type=TXT&name=%s", zoneID, fqdn) - resp, err := d.SendRequest("GET", resource, nil) - if err != nil { - return "", err - } - - var recordSetsRes recordSetsResponse - err = json.NewDecoder(resp).Decode(&recordSetsRes) - if err != nil { - return "", err - } - - if len(recordSetsRes.RecordSets) < 1 { - return "", fmt.Errorf("record not found") - } - - if len(recordSetsRes.RecordSets) > 1 { - return "", fmt.Errorf("to many records found") - } - - if recordSetsRes.RecordSets[0].ID == "" { - return "", fmt.Errorf("id not found") - } - - return recordSetsRes.RecordSets[0].ID, nil -} - -func (d *DNSProvider) deleteRecordSet(zoneID, recordID string) error { - resource := fmt.Sprintf("zones/%s/recordsets/%s", zoneID, recordID) - - _, err := d.SendRequest("DELETE", resource, nil) - if err != nil { - return err - } - return nil -} - -// Present creates a TXT record using the specified parameters -func (d *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - - if ttl < 300 { - ttl = 300 // 300 is otc minimum value for ttl - } - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - err = d.login() - if err != nil { - return err - } - - zoneID, err := d.getZoneID(authZone) - if err != nil { - return fmt.Errorf("unable to get zone: %s", err) - } - - resource := fmt.Sprintf("zones/%s/recordsets", zoneID) - - type recordset struct { - Name string `json:"name"` - Description string `json:"description"` - Type string `json:"type"` - Ttl int `json:"ttl"` - Records []string `json:"records"` - } - - r1 := &recordset{ - Name: fqdn, - Description: "Added TXT record for ACME dns-01 challenge using lego client", - Type: "TXT", - Ttl: 300, - Records: []string{fmt.Sprintf("\"%s\"", value)}, - } - _, err = d.SendRequest("POST", resource, r1) - - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return err - } - - err = d.login() - if err != nil { - return err - } - - zoneID, err := d.getZoneID(authZone) - - if err != nil { - return err - } - - recordID, err := d.getRecordSetID(zoneID, fqdn) - if err != nil { - return fmt.Errorf("unable go get record %s for zone %s: %s", fqdn, domain, err) - } - return d.deleteRecordSet(zoneID, recordID) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/otc/otc_test.go b/vendor/github.com/xenolf/lego/providers/dns/otc/otc_test.go deleted file mode 100644 index 0c05334a9..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/otc/otc_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package otc - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" - "os" - "testing" -) - -type OTCDNSTestSuite struct { - suite.Suite - Mock *DNSMock -} - -func (s *OTCDNSTestSuite) TearDownSuite() { - s.Mock.ShutdownServer() -} - -func (s *OTCDNSTestSuite) SetupTest() { - s.Mock = NewDNSMock(s.T()) - s.Mock.Setup() - s.Mock.HandleAuthSuccessfully() - -} - -func TestOTCDNSTestSuite(t *testing.T) { - suite.Run(t, new(OTCDNSTestSuite)) -} - -func (s *OTCDNSTestSuite) createDNSProvider() (*DNSProvider, error) { - url := fmt.Sprintf("%s/v3/auth/token", s.Mock.Server.URL) - return NewDNSProviderCredentials(fakeOTCUserName, fakeOTCPassword, fakeOTCDomainName, fakeOTCProjectName, url) -} - -func (s *OTCDNSTestSuite) TestOTCDNSLoginEnv() { - os.Setenv("OTC_DOMAIN_NAME", "unittest1") - os.Setenv("OTC_USER_NAME", "unittest2") - os.Setenv("OTC_PASSWORD", "unittest3") - os.Setenv("OTC_PROJECT_NAME", "unittest4") - os.Setenv("OTC_IDENTITY_ENDPOINT", "unittest5") - - provider, err := NewDNSProvider() - assert.Nil(s.T(), err) - assert.Equal(s.T(), provider.domainName, "unittest1") - assert.Equal(s.T(), provider.userName, "unittest2") - assert.Equal(s.T(), provider.password, "unittest3") - assert.Equal(s.T(), provider.projectName, "unittest4") - assert.Equal(s.T(), provider.identityEndpoint, "unittest5") - - os.Setenv("OTC_IDENTITY_ENDPOINT", "") - - provider, err = NewDNSProvider() - assert.Nil(s.T(), err) - assert.Equal(s.T(), provider.identityEndpoint, "https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens") - - os.Clearenv() -} - -func (s *OTCDNSTestSuite) TestOTCDNSLoginEnvEmpty() { - _, err := NewDNSProvider() - assert.Equal(s.T(), "OTC credentials missing", err.Error()) - - os.Clearenv() -} - -func (s *OTCDNSTestSuite) TestOTCDNSLogin() { - otcProvider, err := s.createDNSProvider() - - assert.Nil(s.T(), err) - err = otcProvider.loginRequest() - assert.Nil(s.T(), err) - assert.Equal(s.T(), otcProvider.otcBaseURL, fmt.Sprintf("%s/v2", s.Mock.Server.URL)) - assert.Equal(s.T(), fakeOTCToken, otcProvider.token) -} - -func (s *OTCDNSTestSuite) TestOTCDNSEmptyZone() { - s.Mock.HandleListZonesEmpty() - s.Mock.HandleListRecordsetsSuccessfully() - - otcProvider, _ := s.createDNSProvider() - err := otcProvider.Present("example.com", "", "foobar") - assert.NotNil(s.T(), err) -} - -func (s *OTCDNSTestSuite) TestOTCDNSEmptyRecordset() { - s.Mock.HandleListZonesSuccessfully() - s.Mock.HandleListRecordsetsEmpty() - - otcProvider, _ := s.createDNSProvider() - err := otcProvider.CleanUp("example.com", "", "foobar") - assert.NotNil(s.T(), err) -} - -func (s *OTCDNSTestSuite) TestOTCDNSPresent() { - s.Mock.HandleListZonesSuccessfully() - s.Mock.HandleListRecordsetsSuccessfully() - - otcProvider, _ := s.createDNSProvider() - err := otcProvider.Present("example.com", "", "foobar") - assert.Nil(s.T(), err) -} - -func (s *OTCDNSTestSuite) TestOTCDNSCleanup() { - s.Mock.HandleListZonesSuccessfully() - s.Mock.HandleListRecordsetsSuccessfully() - s.Mock.HandleDeleteRecordsetsSuccessfully() - - otcProvider, _ := s.createDNSProvider() - err := otcProvider.CleanUp("example.com", "", "foobar") - assert.Nil(s.T(), err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go b/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go deleted file mode 100644 index 290a8d7df..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go +++ /dev/null @@ -1,159 +0,0 @@ -// Package OVH implements a DNS provider for solving the DNS-01 -// challenge using OVH DNS. -package ovh - -import ( - "fmt" - "os" - "strings" - "sync" - - "github.com/ovh/go-ovh/ovh" - "github.com/xenolf/lego/acme" -) - -// OVH API reference: https://eu.api.ovh.com/ -// Create a Token: https://eu.api.ovh.com/createToken/ - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -// that uses OVH's REST API to manage TXT records for a domain. -type DNSProvider struct { - client *ovh.Client - recordIDs map[string]int - recordIDsMu sync.Mutex -} - -// NewDNSProvider returns a DNSProvider instance configured for OVH -// Credentials must be passed in the environment variable: -// OVH_ENDPOINT : it must be ovh-eu or ovh-ca -// OVH_APPLICATION_KEY -// OVH_APPLICATION_SECRET -// OVH_CONSUMER_KEY -func NewDNSProvider() (*DNSProvider, error) { - apiEndpoint := os.Getenv("OVH_ENDPOINT") - applicationKey := os.Getenv("OVH_APPLICATION_KEY") - applicationSecret := os.Getenv("OVH_APPLICATION_SECRET") - consumerKey := os.Getenv("OVH_CONSUMER_KEY") - return NewDNSProviderCredentials(apiEndpoint, applicationKey, applicationSecret, consumerKey) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for OVH. -func NewDNSProviderCredentials(apiEndpoint, applicationKey, applicationSecret, consumerKey string) (*DNSProvider, error) { - if apiEndpoint == "" || applicationKey == "" || applicationSecret == "" || consumerKey == "" { - return nil, fmt.Errorf("OVH credentials missing") - } - - ovhClient, _ := ovh.NewClient( - apiEndpoint, - applicationKey, - applicationSecret, - consumerKey, - ) - - return &DNSProvider{ - client: ovhClient, - recordIDs: make(map[string]int), - }, nil -} - -// Present creates a TXT record to fulfil the dns-01 challenge. -func (d *DNSProvider) Present(domain, token, keyAuth string) error { - - // txtRecordRequest represents the request body to DO's API to make a TXT record - type txtRecordRequest struct { - FieldType string `json:"fieldType"` - SubDomain string `json:"subDomain"` - Target string `json:"target"` - TTL int `json:"ttl"` - } - - // txtRecordResponse represents a response from DO's API after making a TXT record - type txtRecordResponse struct { - ID int `json:"id"` - FieldType string `json:"fieldType"` - SubDomain string `json:"subDomain"` - Target string `json:"target"` - TTL int `json:"ttl"` - Zone string `json:"zone"` - } - - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - - // Parse domain name - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - authZone = acme.UnFqdn(authZone) - subDomain := d.extractRecordName(fqdn, authZone) - - reqURL := fmt.Sprintf("/domain/zone/%s/record", authZone) - reqData := txtRecordRequest{FieldType: "TXT", SubDomain: subDomain, Target: value, TTL: ttl} - var respData txtRecordResponse - - // Create TXT record - err = d.client.Post(reqURL, reqData, &respData) - if err != nil { - fmt.Printf("Error when call OVH api to add record : %q \n", err) - return err - } - - // Apply the change - reqURL = fmt.Sprintf("/domain/zone/%s/refresh", authZone) - err = d.client.Post(reqURL, nil, nil) - if err != nil { - fmt.Printf("Error when call OVH api to refresh zone : %q \n", err) - return err - } - - d.recordIDsMu.Lock() - d.recordIDs[fqdn] = respData.ID - d.recordIDsMu.Unlock() - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - // get the record's unique ID from when we created it - d.recordIDsMu.Lock() - recordID, ok := d.recordIDs[fqdn] - d.recordIDsMu.Unlock() - if !ok { - return fmt.Errorf("unknown record ID for '%s'", fqdn) - } - - authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers) - if err != nil { - return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err) - } - - authZone = acme.UnFqdn(authZone) - - reqURL := fmt.Sprintf("/domain/zone/%s/record/%d", authZone, recordID) - - err = d.client.Delete(reqURL, nil) - if err != nil { - fmt.Printf("Error when call OVH api to delete challenge record : %q \n", err) - return err - } - - // Delete record ID from map - d.recordIDsMu.Lock() - delete(d.recordIDs, fqdn) - d.recordIDsMu.Unlock() - - return nil -} - -func (d *DNSProvider) extractRecordName(fqdn, domain string) string { - name := acme.UnFqdn(fqdn) - if idx := strings.Index(name, "."+domain); idx != -1 { - return name[:idx] - } - return name -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh_test.go b/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh_test.go deleted file mode 100644 index 47da60e57..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/ovh/ovh_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package ovh - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - liveTest bool - apiEndpoint string - applicationKey string - applicationSecret string - consumerKey string - domain string -) - -func init() { - apiEndpoint = os.Getenv("OVH_ENDPOINT") - applicationKey = os.Getenv("OVH_APPLICATION_KEY") - applicationSecret = os.Getenv("OVH_APPLICATION_SECRET") - consumerKey = os.Getenv("OVH_CONSUMER_KEY") - liveTest = len(apiEndpoint) > 0 && len(applicationKey) > 0 && len(applicationSecret) > 0 && len(consumerKey) > 0 -} - -func restoreEnv() { - os.Setenv("OVH_ENDPOINT", apiEndpoint) - os.Setenv("OVH_APPLICATION_KEY", applicationKey) - os.Setenv("OVH_APPLICATION_SECRET", applicationSecret) - os.Setenv("OVH_CONSUMER_KEY", consumerKey) -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("OVH_ENDPOINT", "ovh-eu") - os.Setenv("OVH_APPLICATION_KEY", "1234") - os.Setenv("OVH_APPLICATION_SECRET", "5678") - os.Setenv("OVH_CONSUMER_KEY", "abcde") - defer restoreEnv() - _, err := NewDNSProvider() - assert.NoError(t, err) -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("OVH_ENDPOINT", "") - os.Setenv("OVH_APPLICATION_KEY", "1234") - os.Setenv("OVH_APPLICATION_SECRET", "5678") - os.Setenv("OVH_CONSUMER_KEY", "abcde") - defer restoreEnv() - _, err := NewDNSProvider() - assert.EqualError(t, err, "OVH credentials missing") - - os.Setenv("OVH_ENDPOINT", "ovh-eu") - os.Setenv("OVH_APPLICATION_KEY", "") - os.Setenv("OVH_APPLICATION_SECRET", "5678") - os.Setenv("OVH_CONSUMER_KEY", "abcde") - defer restoreEnv() - _, err = NewDNSProvider() - assert.EqualError(t, err, "OVH credentials missing") - - os.Setenv("OVH_ENDPOINT", "ovh-eu") - os.Setenv("OVH_APPLICATION_KEY", "1234") - os.Setenv("OVH_APPLICATION_SECRET", "") - os.Setenv("OVH_CONSUMER_KEY", "abcde") - defer restoreEnv() - _, err = NewDNSProvider() - assert.EqualError(t, err, "OVH credentials missing") - - os.Setenv("OVH_ENDPOINT", "ovh-eu") - os.Setenv("OVH_APPLICATION_KEY", "1234") - os.Setenv("OVH_APPLICATION_SECRET", "5678") - os.Setenv("OVH_CONSUMER_KEY", "") - defer restoreEnv() - _, err = NewDNSProvider() - assert.EqualError(t, err, "OVH credentials missing") -} - -func TestLivePresent(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(domain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveCleanUp(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(domain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/pdns/README.md b/vendor/github.com/xenolf/lego/providers/dns/pdns/README.md deleted file mode 100644 index 23abb7669..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/pdns/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## PowerDNS provider - -Tested and confirmed to work with PowerDNS authoratative server 3.4.8 and 4.0.1. Refer to [PowerDNS documentation](https://doc.powerdns.com/md/httpapi/README/) instructions on how to enable the built-in API interface. - -PowerDNS Notes: -- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc. -- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-API-EDIT` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table diff --git a/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go b/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go deleted file mode 100644 index a4fd22b0c..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go +++ /dev/null @@ -1,343 +0,0 @@ -// Package pdns implements a DNS provider for solving the DNS-01 -// challenge using PowerDNS nameserver. -package pdns - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "strconv" - "strings" - "time" - - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -type DNSProvider struct { - apiKey string - host *url.URL - apiVersion int -} - -// NewDNSProvider returns a DNSProvider instance configured for pdns. -// Credentials must be passed in the environment variable: -// PDNS_API_URL and PDNS_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - key := os.Getenv("PDNS_API_KEY") - hostUrl, err := url.Parse(os.Getenv("PDNS_API_URL")) - if err != nil { - return nil, err - } - - return NewDNSProviderCredentials(hostUrl, key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for pdns. -func NewDNSProviderCredentials(host *url.URL, key string) (*DNSProvider, error) { - if key == "" { - return nil, fmt.Errorf("PDNS API key missing") - } - - if host == nil || host.Host == "" { - return nil, fmt.Errorf("PDNS API URL missing") - } - - provider := &DNSProvider{ - host: host, - apiKey: key, - } - provider.getAPIVersion() - - return provider, 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 -} - -// Present creates a TXT record to fulfil the dns-01 challenge -func (c *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zone, err := c.getHostedZone(fqdn) - if err != nil { - return err - } - - name := fqdn - - // pre-v1 API wants non-fqdn - if c.apiVersion == 0 { - name = acme.UnFqdn(fqdn) - } - - rec := pdnsRecord{ - Content: "\"" + value + "\"", - Disabled: false, - - // pre-v1 API - Type: "TXT", - Name: name, - TTL: 120, - } - - rrsets := rrSets{ - RRSets: []rrSet{ - rrSet{ - Name: name, - ChangeType: "REPLACE", - Type: "TXT", - Kind: "Master", - TTL: 120, - Records: []pdnsRecord{rec}, - }, - }, - } - - body, err := json.Marshal(rrsets) - if err != nil { - return err - } - - _, err = c.makeRequest("PATCH", zone.URL, bytes.NewReader(body)) - if err != nil { - fmt.Println("here") - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - zone, err := c.getHostedZone(fqdn) - if err != nil { - return err - } - - set, err := c.findTxtRecord(fqdn) - if err != nil { - return err - } - - rrsets := rrSets{ - RRSets: []rrSet{ - rrSet{ - Name: set.Name, - Type: set.Type, - ChangeType: "DELETE", - }, - }, - } - body, err := json.Marshal(rrsets) - if err != nil { - return err - } - - _, err = c.makeRequest("PATCH", zone.URL, bytes.NewReader(body)) - if err != nil { - return err - } - - return nil -} - -func (c *DNSProvider) getHostedZone(fqdn string) (*hostedZone, error) { - var zone hostedZone - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return nil, err - } - - url := "/servers/localhost/zones" - result, err := c.makeRequest("GET", url, nil) - if err != nil { - return nil, err - } - - zones := []hostedZone{} - err = json.Unmarshal(result, &zones) - if err != nil { - return nil, err - } - - url = "" - for _, zone := range zones { - if acme.UnFqdn(zone.Name) == acme.UnFqdn(authZone) { - url = zone.URL - } - } - - result, err = c.makeRequest("GET", url, nil) - if err != nil { - return nil, err - } - - err = json.Unmarshal(result, &zone) - if err != nil { - return nil, err - } - - // convert pre-v1 API result - if len(zone.Records) > 0 { - zone.RRSets = []rrSet{} - for _, record := range zone.Records { - set := rrSet{ - Name: record.Name, - Type: record.Type, - Records: []pdnsRecord{record}, - } - zone.RRSets = append(zone.RRSets, set) - } - } - - return &zone, nil -} - -func (c *DNSProvider) findTxtRecord(fqdn string) (*rrSet, error) { - zone, err := c.getHostedZone(fqdn) - if err != nil { - return nil, err - } - - _, err = c.makeRequest("GET", zone.URL, nil) - if err != nil { - return nil, err - } - - for _, set := range zone.RRSets { - if (set.Name == acme.UnFqdn(fqdn) || set.Name == fqdn) && set.Type == "TXT" { - return &set, nil - } - } - - return nil, fmt.Errorf("No existing record found for %s", fqdn) -} - -func (c *DNSProvider) getAPIVersion() { - type APIVersion struct { - URL string `json:"url"` - Version int `json:"version"` - } - - result, err := c.makeRequest("GET", "/api", nil) - if err != nil { - return - } - - var versions []APIVersion - err = json.Unmarshal(result, &versions) - if err != nil { - return - } - - latestVersion := 0 - for _, v := range versions { - if v.Version > latestVersion { - latestVersion = v.Version - } - } - c.apiVersion = latestVersion -} - -func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) { - type APIError struct { - Error string `json:"error"` - } - var path = "" - if c.host.Path != "/" { - path = c.host.Path - } - if c.apiVersion > 0 { - if !strings.HasPrefix(uri, "api/v") { - uri = "/api/v" + strconv.Itoa(c.apiVersion) + uri - } else { - uri = "/" + uri - } - } - url := c.host.Scheme + "://" + c.host.Host + path + uri - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, err - } - - req.Header.Set("X-API-Key", c.apiKey) - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error talking to PDNS API -> %v", err) - } - - defer resp.Body.Close() - - if resp.StatusCode != 422 && (resp.StatusCode < 200 || resp.StatusCode >= 300) { - return nil, fmt.Errorf("Unexpected HTTP status code %d when fetching '%s'", resp.StatusCode, url) - } - - var msg json.RawMessage - err = json.NewDecoder(resp.Body).Decode(&msg) - switch { - case err == io.EOF: - // empty body - return nil, nil - case err != nil: - // other error - return nil, err - } - - // check for PowerDNS error message - if len(msg) > 0 && msg[0] == '{' { - var apiError APIError - err = json.Unmarshal(msg, &apiError) - if err != nil { - return nil, err - } - if apiError.Error != "" { - return nil, fmt.Errorf("Error talking to PDNS API -> %v", apiError.Error) - } - } - return msg, nil -} - -type pdnsRecord struct { - Content string `json:"content"` - Disabled bool `json:"disabled"` - - // pre-v1 API - Name string `json:"name"` - Type string `json:"type"` - TTL int `json:"ttl,omitempty"` -} - -type hostedZone struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - RRSets []rrSet `json:"rrsets"` - - // pre-v1 API - Records []pdnsRecord `json:"records"` -} - -type rrSet struct { - Name string `json:"name"` - Type string `json:"type"` - Kind string `json:"kind"` - ChangeType string `json:"changetype"` - Records []pdnsRecord `json:"records"` - TTL int `json:"ttl,omitempty"` -} - -type rrSets struct { - RRSets []rrSet `json:"rrsets"` -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns_test.go b/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns_test.go deleted file mode 100644 index 70e7670ed..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/pdns/pdns_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package pdns - -import ( - "net/url" - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - pdnsLiveTest bool - pdnsURL *url.URL - pdnsURLStr string - pdnsAPIKey string - pdnsDomain string -) - -func init() { - pdnsURLStr = os.Getenv("PDNS_API_URL") - pdnsURL, _ = url.Parse(pdnsURLStr) - pdnsAPIKey = os.Getenv("PDNS_API_KEY") - pdnsDomain = os.Getenv("PDNS_DOMAIN") - if len(pdnsURLStr) > 0 && len(pdnsAPIKey) > 0 && len(pdnsDomain) > 0 { - pdnsLiveTest = true - } -} - -func restorePdnsEnv() { - os.Setenv("PDNS_API_URL", pdnsURLStr) - os.Setenv("PDNS_API_KEY", pdnsAPIKey) -} - -func TestNewDNSProviderValid(t *testing.T) { - os.Setenv("PDNS_API_URL", "") - os.Setenv("PDNS_API_KEY", "") - tmpURL, _ := url.Parse("http://localhost:8081") - _, err := NewDNSProviderCredentials(tmpURL, "123") - assert.NoError(t, err) - restorePdnsEnv() -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("PDNS_API_URL", "http://localhost:8081") - os.Setenv("PDNS_API_KEY", "123") - _, err := NewDNSProvider() - assert.NoError(t, err) - restorePdnsEnv() -} - -func TestNewDNSProviderMissingHostErr(t *testing.T) { - os.Setenv("PDNS_API_URL", "") - os.Setenv("PDNS_API_KEY", "123") - _, err := NewDNSProvider() - assert.EqualError(t, err, "PDNS API URL missing") - restorePdnsEnv() -} - -func TestNewDNSProviderMissingKeyErr(t *testing.T) { - os.Setenv("PDNS_API_URL", pdnsURLStr) - os.Setenv("PDNS_API_KEY", "") - _, err := NewDNSProvider() - assert.EqualError(t, err, "PDNS API key missing") - restorePdnsEnv() -} - -func TestPdnsPresentAndCleanup(t *testing.T) { - if !pdnsLiveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProviderCredentials(pdnsURL, pdnsAPIKey) - assert.NoError(t, err) - - err = provider.Present(pdnsDomain, "", "123d==") - assert.NoError(t, err) - - err = provider.CleanUp(pdnsDomain, "", "123d==") - assert.NoError(t, err) -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go b/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go deleted file mode 100644 index 13daa8c8a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go +++ /dev/null @@ -1,284 +0,0 @@ -// Package rackspace implements a DNS provider for solving the DNS-01 -// challenge using rackspace DNS. -package rackspace - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "time" - - "github.com/xenolf/lego/acme" -) - -// rackspaceAPIURL represents the Identity API endpoint to call -var rackspaceAPIURL = "https://identity.api.rackspacecloud.com/v2.0/tokens" - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -// used to store the reusable token and DNS API endpoint -type DNSProvider struct { - token string - cloudDNSEndpoint string -} - -// NewDNSProvider returns a DNSProvider instance configured for Rackspace. -// Credentials must be passed in the environment variables: RACKSPACE_USER -// and RACKSPACE_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - user := os.Getenv("RACKSPACE_USER") - key := os.Getenv("RACKSPACE_API_KEY") - return NewDNSProviderCredentials(user, key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Rackspace. It authenticates against -// the API, also grabbing the DNS Endpoint. -func NewDNSProviderCredentials(user, key string) (*DNSProvider, error) { - if user == "" || key == "" { - return nil, fmt.Errorf("Rackspace credentials missing") - } - - type APIKeyCredentials struct { - Username string `json:"username"` - APIKey string `json:"apiKey"` - } - - type Auth struct { - APIKeyCredentials `json:"RAX-KSKEY:apiKeyCredentials"` - } - - type RackspaceAuthData struct { - Auth `json:"auth"` - } - - type RackspaceIdentity struct { - Access struct { - ServiceCatalog []struct { - Endpoints []struct { - PublicURL string `json:"publicURL"` - TenantID string `json:"tenantId"` - } `json:"endpoints"` - Name string `json:"name"` - } `json:"serviceCatalog"` - Token struct { - ID string `json:"id"` - } `json:"token"` - } `json:"access"` - } - - authData := RackspaceAuthData{ - Auth: Auth{ - APIKeyCredentials: APIKeyCredentials{ - Username: user, - APIKey: key, - }, - }, - } - - body, err := json.Marshal(authData) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", rackspaceAPIURL, bytes.NewReader(body)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error querying Rackspace Identity API: %v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("Rackspace Authentication failed. Response code: %d", resp.StatusCode) - } - - var rackspaceIdentity RackspaceIdentity - err = json.NewDecoder(resp.Body).Decode(&rackspaceIdentity) - if err != nil { - return nil, err - } - - // Iterate through the Service Catalog to get the DNS Endpoint - var dnsEndpoint string - for _, service := range rackspaceIdentity.Access.ServiceCatalog { - if service.Name == "cloudDNS" { - dnsEndpoint = service.Endpoints[0].PublicURL - break - } - } - if dnsEndpoint == "" { - return nil, fmt.Errorf("Failed to populate DNS endpoint, check Rackspace API for changes.") - } - - return &DNSProvider{ - token: rackspaceIdentity.Access.Token.ID, - cloudDNSEndpoint: dnsEndpoint, - }, nil -} - -// Present creates a TXT record to fulfil the dns-01 challenge -func (c *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - rec := RackspaceRecords{ - RackspaceRecord: []RackspaceRecord{{ - Name: acme.UnFqdn(fqdn), - Type: "TXT", - Data: value, - TTL: 300, - }}, - } - - body, err := json.Marshal(rec) - if err != nil { - return err - } - - _, err = c.makeRequest("POST", fmt.Sprintf("/domains/%d/records", zoneID), bytes.NewReader(body)) - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - record, err := c.findTxtRecord(fqdn, zoneID) - if err != nil { - return err - } - - _, err = c.makeRequest("DELETE", fmt.Sprintf("/domains/%d/records?id=%s", zoneID, record.ID), nil) - if err != nil { - return err - } - - return nil -} - -// getHostedZoneID performs a lookup to get the DNS zone which needs -// modifying for a given FQDN -func (c *DNSProvider) getHostedZoneID(fqdn string) (int, error) { - // HostedZones represents the response when querying Rackspace DNS zones - type ZoneSearchResponse struct { - TotalEntries int `json:"totalEntries"` - HostedZones []struct { - ID int `json:"id"` - Name string `json:"name"` - } `json:"domains"` - } - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return 0, err - } - - result, err := c.makeRequest("GET", fmt.Sprintf("/domains?name=%s", acme.UnFqdn(authZone)), nil) - if err != nil { - return 0, err - } - - var zoneSearchResponse ZoneSearchResponse - err = json.Unmarshal(result, &zoneSearchResponse) - if err != nil { - return 0, err - } - - // If nothing was returned, or for whatever reason more than 1 was returned (the search uses exact match, so should not occur) - if zoneSearchResponse.TotalEntries != 1 { - return 0, fmt.Errorf("Found %d zones for %s in Rackspace for domain %s", zoneSearchResponse.TotalEntries, authZone, fqdn) - } - - return zoneSearchResponse.HostedZones[0].ID, nil -} - -// findTxtRecord searches a DNS zone for a TXT record with a specific name -func (c *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*RackspaceRecord, error) { - result, err := c.makeRequest("GET", fmt.Sprintf("/domains/%d/records?type=TXT&name=%s", zoneID, acme.UnFqdn(fqdn)), nil) - if err != nil { - return nil, err - } - - var records RackspaceRecords - err = json.Unmarshal(result, &records) - if err != nil { - return nil, err - } - - recordsLength := len(records.RackspaceRecord) - switch recordsLength { - case 1: - break - case 0: - return nil, fmt.Errorf("No TXT record found for %s", fqdn) - default: - return nil, fmt.Errorf("More than 1 TXT record found for %s", fqdn) - } - - return &records.RackspaceRecord[0], nil -} - -// makeRequest is a wrapper function used for making DNS API requests -func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) { - url := c.cloudDNSEndpoint + uri - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, err - } - - req.Header.Set("X-Auth-Token", c.token) - req.Header.Set("Content-Type", "application/json") - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error querying DNS API: %v", err) - } - - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { - return nil, fmt.Errorf("Request failed for %s %s. Response code: %d", method, url, resp.StatusCode) - } - - var r json.RawMessage - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, fmt.Errorf("JSON decode failed for %s %s. Response code: %d", method, url, resp.StatusCode) - } - - return r, nil -} - -// RackspaceRecords is the list of records sent/received from the DNS API -type RackspaceRecords struct { - RackspaceRecord []RackspaceRecord `json:"records"` -} - -// RackspaceRecord represents a Rackspace DNS record -type RackspaceRecord struct { - Name string `json:"name"` - Type string `json:"type"` - Data string `json:"data"` - TTL int `json:"ttl,omitempty"` - ID string `json:"id,omitempty"` -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go b/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go deleted file mode 100644 index 22c979cad..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package rackspace - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - rackspaceLiveTest bool - rackspaceUser string - rackspaceAPIKey string - rackspaceDomain string - testAPIURL string -) - -func init() { - rackspaceUser = os.Getenv("RACKSPACE_USER") - rackspaceAPIKey = os.Getenv("RACKSPACE_API_KEY") - rackspaceDomain = os.Getenv("RACKSPACE_DOMAIN") - if len(rackspaceUser) > 0 && len(rackspaceAPIKey) > 0 && len(rackspaceDomain) > 0 { - rackspaceLiveTest = true - } -} - -func testRackspaceEnv() { - rackspaceAPIURL = testAPIURL - os.Setenv("RACKSPACE_USER", "testUser") - os.Setenv("RACKSPACE_API_KEY", "testKey") -} - -func liveRackspaceEnv() { - rackspaceAPIURL = "https://identity.api.rackspacecloud.com/v2.0/tokens" - os.Setenv("RACKSPACE_USER", rackspaceUser) - os.Setenv("RACKSPACE_API_KEY", rackspaceAPIKey) -} - -func startTestServers() (identityAPI, dnsAPI *httptest.Server) { - dnsAPI = httptest.NewServer(dnsMux()) - dnsEndpoint := dnsAPI.URL + "/123456" - - identityAPI = httptest.NewServer(identityHandler(dnsEndpoint)) - testAPIURL = identityAPI.URL + "/" - return -} - -func closeTestServers(identityAPI, dnsAPI *httptest.Server) { - identityAPI.Close() - dnsAPI.Close() -} - -func identityHandler(dnsEndpoint string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - resp, found := jsonMap[string(reqBody)] - if !found { - w.WriteHeader(http.StatusBadRequest) - return - } - resp = strings.Replace(resp, "https://dns.api.rackspacecloud.com/v1.0/123456", dnsEndpoint, 1) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, resp) - }) -} - -func dnsMux() *http.ServeMux { - mux := http.NewServeMux() - - // Used by `getHostedZoneID()` finding `zoneID` "?name=example.com" - mux.HandleFunc("/123456/domains", func(w http.ResponseWriter, r *http.Request) { - if r.URL.Query().Get("name") == "example.com" { - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, jsonMap["zoneDetails"]) - return - } - w.WriteHeader(http.StatusBadRequest) - return - }) - - mux.HandleFunc("/123456/domains/112233/records", func(w http.ResponseWriter, r *http.Request) { - switch r.Method { - // Used by `Present()` creating the TXT record - case http.MethodPost: - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - resp, found := jsonMap[string(reqBody)] - if !found { - w.WriteHeader(http.StatusBadRequest) - return - } - w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, resp) - // Used by `findTxtRecord()` finding `record.ID` "?type=TXT&name=_acme-challenge.example.com" - case http.MethodGet: - if r.URL.Query().Get("type") == "TXT" && r.URL.Query().Get("name") == "_acme-challenge.example.com" { - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, jsonMap["recordDetails"]) - return - } - w.WriteHeader(http.StatusBadRequest) - return - // Used by `CleanUp()` deleting the TXT record "?id=445566" - case http.MethodDelete: - if r.URL.Query().Get("id") == "TXT-654321" { - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, jsonMap["recordDelete"]) - return - } - w.WriteHeader(http.StatusBadRequest) - } - }) - - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotFound) - fmt.Printf("Not Found for Request: (%+v)\n\n", r) - }) - - return mux -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - testRackspaceEnv() - _, err := NewDNSProviderCredentials("", "") - assert.EqualError(t, err, "Rackspace credentials missing") -} - -func TestOfflineRackspaceValid(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProviderCredentials(os.Getenv("RACKSPACE_USER"), os.Getenv("RACKSPACE_API_KEY")) - - assert.NoError(t, err) - assert.Equal(t, provider.token, "testToken", "The token should match") -} - -func TestOfflineRackspacePresent(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProvider() - - if assert.NoError(t, err) { - err = provider.Present("example.com", "token", "keyAuth") - assert.NoError(t, err) - } -} - -func TestOfflineRackspaceCleanUp(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProvider() - - if assert.NoError(t, err) { - err = provider.CleanUp("example.com", "token", "keyAuth") - assert.NoError(t, err) - } -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base") -} - -func TestRackspacePresent(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(rackspaceDomain, "", "112233445566==") - assert.NoError(t, err) -} - -func TestRackspaceCleanUp(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 15) - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(rackspaceDomain, "", "112233445566==") - assert.NoError(t, err) -} - -func TestMain(m *testing.M) { - identityAPI, dnsAPI := startTestServers() - defer closeTestServers(identityAPI, dnsAPI) - os.Exit(m.Run()) -} - -var jsonMap = map[string]string{ - `{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"testUser","apiKey":"testKey"}}}`: `{"access":{"token":{"id":"testToken","expires":"1970-01-01T00:00:00.000Z","tenant":{"id":"123456","name":"123456"},"RAX-AUTH:authenticatedBy":["APIKEY"]},"serviceCatalog":[{"type":"rax:dns","endpoints":[{"publicURL":"https://dns.api.rackspacecloud.com/v1.0/123456","tenantId":"123456"}],"name":"cloudDNS"}],"user":{"id":"fakeUseID","name":"testUser"}}}`, - "zoneDetails": `{"domains":[{"name":"example.com","id":112233,"emailAddress":"hostmaster@example.com","updated":"1970-01-01T00:00:00.000+0000","created":"1970-01-01T00:00:00.000+0000"}],"totalEntries":1}`, - `{"records":[{"name":"_acme-challenge.example.com","type":"TXT","data":"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM","ttl":300}]}`: `{"request":"{\"records\":[{\"name\":\"_acme-challenge.example.com\",\"type\":\"TXT\",\"data\":\"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM\",\"ttl\":300}]}","status":"RUNNING","verb":"POST","jobId":"00000000-0000-0000-0000-0000000000","callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/status/00000000-0000-0000-0000-0000000000","requestUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/domains/112233/records"}`, - "recordDetails": `{"records":[{"name":"_acme-challenge.example.com","id":"TXT-654321","type":"TXT","data":"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM","ttl":300,"updated":"1970-01-01T00:00:00.000+0000","created":"1970-01-01T00:00:00.000+0000"}]}`, - "recordDelete": `{"status":"RUNNING","verb":"DELETE","jobId":"00000000-0000-0000-0000-0000000000","callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/status/00000000-0000-0000-0000-0000000000","requestUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/domains/112233/recordsid=TXT-654321"}`, -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go b/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go deleted file mode 100644 index dde42ddf1..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go +++ /dev/null @@ -1,152 +0,0 @@ -// Package rfc2136 implements a DNS provider for solving the DNS-01 challenge -// using the rfc2136 dynamic update. -package rfc2136 - -import ( - "fmt" - "net" - "os" - "strings" - "time" - - "github.com/miekg/dns" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface that -// uses dynamic DNS updates (RFC 2136) to create TXT records on a nameserver. -type DNSProvider struct { - nameserver string - tsigAlgorithm string - tsigKey string - tsigSecret string - timeout time.Duration -} - -// NewDNSProvider returns a DNSProvider instance configured for rfc2136 -// dynamic update. Configured with environment variables: -// RFC2136_NAMESERVER: Network address in the form "host" or "host:port". -// RFC2136_TSIG_ALGORITHM: Defaults to hmac-md5.sig-alg.reg.int. (HMAC-MD5). -// See https://github.com/miekg/dns/blob/master/tsig.go for supported values. -// RFC2136_TSIG_KEY: Name of the secret key as defined in DNS server configuration. -// RFC2136_TSIG_SECRET: Secret key payload. -// RFC2136_TIMEOUT: DNS propagation timeout in time.ParseDuration format. (60s) -// To disable TSIG authentication, leave the RFC2136_TSIG* variables unset. -func NewDNSProvider() (*DNSProvider, error) { - nameserver := os.Getenv("RFC2136_NAMESERVER") - tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM") - tsigKey := os.Getenv("RFC2136_TSIG_KEY") - tsigSecret := os.Getenv("RFC2136_TSIG_SECRET") - timeout := os.Getenv("RFC2136_TIMEOUT") - return NewDNSProviderCredentials(nameserver, tsigAlgorithm, tsigKey, tsigSecret, timeout) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for rfc2136 dynamic update. To disable TSIG -// authentication, leave the TSIG parameters as empty strings. -// nameserver must be a network address in the form "host" or "host:port". -func NewDNSProviderCredentials(nameserver, tsigAlgorithm, tsigKey, tsigSecret, timeout string) (*DNSProvider, error) { - if nameserver == "" { - return nil, fmt.Errorf("RFC2136 nameserver missing") - } - - // Append the default DNS port if none is specified. - if _, _, err := net.SplitHostPort(nameserver); err != nil { - if strings.Contains(err.Error(), "missing port") { - nameserver = net.JoinHostPort(nameserver, "53") - } else { - return nil, err - } - } - d := &DNSProvider{ - nameserver: nameserver, - } - if tsigAlgorithm == "" { - tsigAlgorithm = dns.HmacMD5 - } - d.tsigAlgorithm = tsigAlgorithm - if len(tsigKey) > 0 && len(tsigSecret) > 0 { - d.tsigKey = tsigKey - d.tsigSecret = tsigSecret - } - - if timeout == "" { - d.timeout = 60 * time.Second - } else { - t, err := time.ParseDuration(timeout) - if err != nil { - return nil, err - } else if t < 0 { - return nil, fmt.Errorf("Invalid/negative RFC2136_TIMEOUT: %v", timeout) - } else { - d.timeout = t - } - } - - return d, nil -} - -// Returns the timeout configured with RFC2136_TIMEOUT, or 60s. -func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { - return d.timeout, 2 * time.Second -} - -// Present creates a TXT record using the specified parameters -func (r *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - return r.changeRecord("INSERT", fqdn, value, ttl) -} - -// CleanUp removes the TXT record matching the specified parameters -func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, value, ttl := acme.DNS01Record(domain, keyAuth) - return r.changeRecord("REMOVE", fqdn, value, ttl) -} - -func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error { - // Find the zone for the given fqdn - zone, err := acme.FindZoneByFqdn(fqdn, []string{r.nameserver}) - if err != nil { - return err - } - - // Create RR - rr := new(dns.TXT) - rr.Hdr = dns.RR_Header{Name: fqdn, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: uint32(ttl)} - rr.Txt = []string{value} - rrs := []dns.RR{rr} - - // Create dynamic update packet - m := new(dns.Msg) - m.SetUpdate(zone) - switch action { - case "INSERT": - // Always remove old challenge left over from who knows what. - m.RemoveRRset(rrs) - m.Insert(rrs) - case "REMOVE": - m.Remove(rrs) - default: - return fmt.Errorf("Unexpected action: %s", action) - } - - // Setup client - c := new(dns.Client) - c.SingleInflight = true - // TSIG authentication / msg signing - if len(r.tsigKey) > 0 && len(r.tsigSecret) > 0 { - m.SetTsig(dns.Fqdn(r.tsigKey), r.tsigAlgorithm, 300, time.Now().Unix()) - c.TsigSecret = map[string]string{dns.Fqdn(r.tsigKey): r.tsigSecret} - } - - // Send the query - reply, _, err := c.Exchange(m, r.nameserver) - if err != nil { - return fmt.Errorf("DNS update failed: %v", err) - } - if reply != nil && reply.Rcode != dns.RcodeSuccess { - return fmt.Errorf("DNS update failed. Server replied: %s", dns.RcodeToString[reply.Rcode]) - } - - return nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136_test.go b/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136_test.go deleted file mode 100644 index f3ca65b31..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136_test.go +++ /dev/null @@ -1,244 +0,0 @@ -package rfc2136 - -import ( - "bytes" - "fmt" - "net" - "strings" - "sync" - "testing" - "time" - - "github.com/miekg/dns" - "github.com/xenolf/lego/acme" -) - -var ( - rfc2136TestDomain = "123456789.www.example.com" - rfc2136TestKeyAuth = "123d==" - rfc2136TestValue = "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo" - rfc2136TestFqdn = "_acme-challenge.123456789.www.example.com." - rfc2136TestZone = "example.com." - rfc2136TestTTL = 120 - rfc2136TestTsigKey = "example.com." - rfc2136TestTsigSecret = "IwBTJx9wrDp4Y1RyC3H0gA==" -) - -var reqChan = make(chan *dns.Msg, 10) - -func TestRFC2136CanaryLocalTestServer(t *testing.T) { - acme.ClearFqdnCache() - dns.HandleFunc("example.com.", serverHandlerHello) - defer dns.HandleRemove("example.com.") - - server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) - if err != nil { - t.Fatalf("Failed to start test server: %v", err) - } - defer server.Shutdown() - - c := new(dns.Client) - m := new(dns.Msg) - m.SetQuestion("example.com.", dns.TypeTXT) - r, _, err := c.Exchange(m, addrstr) - if err != nil || len(r.Extra) == 0 { - t.Fatalf("Failed to communicate with test server: %v", err) - } - txt := r.Extra[0].(*dns.TXT).Txt[0] - if txt != "Hello world" { - t.Error("Expected test server to return 'Hello world' but got: ", txt) - } -} - -func TestRFC2136ServerSuccess(t *testing.T) { - acme.ClearFqdnCache() - dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) - defer dns.HandleRemove(rfc2136TestZone) - - server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) - if err != nil { - t.Fatalf("Failed to start test server: %v", err) - } - defer server.Shutdown() - - provider, err := NewDNSProviderCredentials(addrstr, "", "", "", "") - if err != nil { - t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err) - } - if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil { - t.Errorf("Expected Present() to return no error but the error was -> %v", err) - } -} - -func TestRFC2136ServerError(t *testing.T) { - acme.ClearFqdnCache() - dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr) - defer dns.HandleRemove(rfc2136TestZone) - - server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) - if err != nil { - t.Fatalf("Failed to start test server: %v", err) - } - defer server.Shutdown() - - provider, err := NewDNSProviderCredentials(addrstr, "", "", "", "") - if err != nil { - t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err) - } - if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err == nil { - t.Errorf("Expected Present() to return an error but it did not.") - } else if !strings.Contains(err.Error(), "NOTZONE") { - t.Errorf("Expected Present() to return an error with the 'NOTZONE' rcode string but it did not.") - } -} - -func TestRFC2136TsigClient(t *testing.T) { - acme.ClearFqdnCache() - dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) - defer dns.HandleRemove(rfc2136TestZone) - - server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", true) - if err != nil { - t.Fatalf("Failed to start test server: %v", err) - } - defer server.Shutdown() - - provider, err := NewDNSProviderCredentials(addrstr, "", rfc2136TestTsigKey, rfc2136TestTsigSecret, "") - if err != nil { - t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err) - } - if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil { - t.Errorf("Expected Present() to return no error but the error was -> %v", err) - } -} - -func TestRFC2136ValidUpdatePacket(t *testing.T) { - acme.ClearFqdnCache() - dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest) - defer dns.HandleRemove(rfc2136TestZone) - - server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) - if err != nil { - t.Fatalf("Failed to start test server: %v", err) - } - defer server.Shutdown() - - txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue)) - rrs := []dns.RR{txtRR} - m := new(dns.Msg) - m.SetUpdate(rfc2136TestZone) - m.RemoveRRset(rrs) - m.Insert(rrs) - expectstr := m.String() - expect, err := m.Pack() - if err != nil { - t.Fatalf("Error packing expect msg: %v", err) - } - - provider, err := NewDNSProviderCredentials(addrstr, "", "", "", "") - if err != nil { - t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err) - } - - if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil { - t.Errorf("Expected Present() to return no error but the error was -> %v", err) - } - - rcvMsg := <-reqChan - rcvMsg.Id = m.Id - actual, err := rcvMsg.Pack() - if err != nil { - t.Fatalf("Error packing actual msg: %v", err) - } - - if !bytes.Equal(actual, expect) { - tmp := new(dns.Msg) - if err := tmp.Unpack(actual); err != nil { - t.Fatalf("Error unpacking actual msg: %v", err) - } - t.Errorf("Expected msg:\n%s", expectstr) - t.Errorf("Actual msg:\n%v", tmp) - } -} - -func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, error) { - pc, err := net.ListenPacket("udp", listenAddr) - if err != nil { - return nil, "", err - } - server := &dns.Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour} - if tsig { - server.TsigSecret = map[string]string{rfc2136TestTsigKey: rfc2136TestTsigSecret} - } - - waitLock := sync.Mutex{} - waitLock.Lock() - server.NotifyStartedFunc = waitLock.Unlock - - go func() { - server.ActivateAndServe() - pc.Close() - }() - - waitLock.Lock() - return server, pc.LocalAddr().String(), nil -} - -func serverHandlerHello(w dns.ResponseWriter, req *dns.Msg) { - m := new(dns.Msg) - m.SetReply(req) - m.Extra = make([]dns.RR, 1) - m.Extra[0] = &dns.TXT{ - Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, - Txt: []string{"Hello world"}, - } - w.WriteMsg(m) -} - -func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) { - m := new(dns.Msg) - m.SetReply(req) - if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET { - // Return SOA to appease findZoneByFqdn() - soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", rfc2136TestZone, rfc2136TestTTL, rfc2136TestZone, rfc2136TestZone)) - m.Answer = []dns.RR{soaRR} - } - - if t := req.IsTsig(); t != nil { - if w.TsigStatus() == nil { - // Validated - m.SetTsig(rfc2136TestZone, dns.HmacMD5, 300, time.Now().Unix()) - } - } - - w.WriteMsg(m) -} - -func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) { - m := new(dns.Msg) - m.SetRcode(req, dns.RcodeNotZone) - w.WriteMsg(m) -} - -func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) { - m := new(dns.Msg) - m.SetReply(req) - if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET { - // Return SOA to appease findZoneByFqdn() - soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", rfc2136TestZone, rfc2136TestTTL, rfc2136TestZone, rfc2136TestZone)) - m.Answer = []dns.RR{soaRR} - } - - if t := req.IsTsig(); t != nil { - if w.TsigStatus() == nil { - // Validated - m.SetTsig(rfc2136TestZone, dns.HmacMD5, 300, time.Now().Unix()) - } - } - - w.WriteMsg(m) - if req.Opcode != dns.OpcodeQuery || req.Question[0].Qtype != dns.TypeSOA || req.Question[0].Qclass != dns.ClassINET { - // Only talk back when it is not the SOA RR. - reqChan <- req - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/route53/fixtures_test.go b/vendor/github.com/xenolf/lego/providers/dns/route53/fixtures_test.go deleted file mode 100644 index a5cc9c878..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/route53/fixtures_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package route53 - -var ChangeResourceRecordSetsResponse = ` - - - /change/123456 - PENDING - 2016-02-10T01:36:41.958Z - -` - -var ListHostedZonesByNameResponse = ` - - - - /hostedzone/ABCDEFG - example.com. - D2224C5B-684A-DB4A-BB9A-E09E3BAFEA7A - - Test comment - false - - 10 - - - true - example2.com - ZLT12321321124 - 1 -` - -var GetChangeResponse = ` - - - 123456 - INSYNC - 2016-02-10T01:36:41.958Z - -` diff --git a/vendor/github.com/xenolf/lego/providers/dns/route53/route53.go b/vendor/github.com/xenolf/lego/providers/dns/route53/route53.go deleted file mode 100644 index 934f0a2d4..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/route53/route53.go +++ /dev/null @@ -1,185 +0,0 @@ -// Package route53 implements a DNS provider for solving the DNS-01 challenge -// using AWS Route 53 DNS. -package route53 - -import ( - "fmt" - "math/rand" - "os" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/xenolf/lego/acme" -) - -const ( - maxRetries = 5 - route53TTL = 10 -) - -// DNSProvider implements the acme.ChallengeProvider interface -type DNSProvider struct { - client *route53.Route53 - hostedZoneID string -} - -// customRetryer implements the client.Retryer interface by composing the -// DefaultRetryer. It controls the logic for retrying recoverable request -// errors (e.g. when rate limits are exceeded). -type customRetryer struct { - client.DefaultRetryer -} - -// RetryRules overwrites the DefaultRetryer's method. -// It uses a basic exponential backoff algorithm that returns an initial -// delay of ~400ms with an upper limit of ~30 seconds which should prevent -// causing a high number of consecutive throttling errors. -// For reference: Route 53 enforces an account-wide(!) 5req/s query limit. -func (d customRetryer) RetryRules(r *request.Request) time.Duration { - retryCount := r.RetryCount - if retryCount > 7 { - retryCount = 7 - } - - delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200) - return time.Duration(delay) * time.Millisecond -} - -// NewDNSProvider returns a DNSProvider instance configured for the AWS -// Route 53 service. -// -// AWS Credentials are automatically detected in the following locations -// and prioritized in the following order: -// 1. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, -// AWS_REGION, [AWS_SESSION_TOKEN] -// 2. Shared credentials file (defaults to ~/.aws/credentials) -// 3. Amazon EC2 IAM role -// -// If AWS_HOSTED_ZONE_ID is not set, Lego tries to determine the correct -// public hosted zone via the FQDN. -// -// See also: https://github.com/aws/aws-sdk-go/wiki/configuring-sdk -func NewDNSProvider() (*DNSProvider, error) { - hostedZoneID := os.Getenv("AWS_HOSTED_ZONE_ID") - - r := customRetryer{} - r.NumMaxRetries = maxRetries - config := request.WithRetryer(aws.NewConfig(), r) - client := route53.New(session.New(config)) - - return &DNSProvider{ - client: client, - hostedZoneID: hostedZoneID, - }, nil -} - -// Present creates a TXT record using the specified parameters -func (r *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - value = `"` + value + `"` - return r.changeRecord("UPSERT", fqdn, value, route53TTL) -} - -// CleanUp removes the TXT record matching the specified parameters -func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - value = `"` + value + `"` - return r.changeRecord("DELETE", fqdn, value, route53TTL) -} - -func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error { - hostedZoneID, err := r.getHostedZoneID(fqdn) - if err != nil { - return fmt.Errorf("Failed to determine Route 53 hosted zone ID: %v", err) - } - - recordSet := newTXTRecordSet(fqdn, value, ttl) - reqParams := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String(hostedZoneID), - ChangeBatch: &route53.ChangeBatch{ - Comment: aws.String("Managed by Lego"), - Changes: []*route53.Change{ - { - Action: aws.String(action), - ResourceRecordSet: recordSet, - }, - }, - }, - } - - resp, err := r.client.ChangeResourceRecordSets(reqParams) - if err != nil { - return fmt.Errorf("Failed to change Route 53 record set: %v", err) - } - - statusID := resp.ChangeInfo.Id - - return acme.WaitFor(120*time.Second, 4*time.Second, func() (bool, error) { - reqParams := &route53.GetChangeInput{ - Id: statusID, - } - resp, err := r.client.GetChange(reqParams) - if err != nil { - return false, fmt.Errorf("Failed to query Route 53 change status: %v", err) - } - if *resp.ChangeInfo.Status == route53.ChangeStatusInsync { - return true, nil - } - return false, nil - }) -} - -func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) { - if r.hostedZoneID != "" { - return r.hostedZoneID, nil - } - - authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) - if err != nil { - return "", err - } - - // .DNSName should not have a trailing dot - reqParams := &route53.ListHostedZonesByNameInput{ - DNSName: aws.String(acme.UnFqdn(authZone)), - } - resp, err := r.client.ListHostedZonesByName(reqParams) - if err != nil { - return "", err - } - - var hostedZoneID string - for _, hostedZone := range resp.HostedZones { - // .Name has a trailing dot - if !*hostedZone.Config.PrivateZone && *hostedZone.Name == authZone { - hostedZoneID = *hostedZone.Id - break - } - } - - if len(hostedZoneID) == 0 { - return "", fmt.Errorf("Zone %s not found in Route 53 for domain %s", authZone, fqdn) - } - - if strings.HasPrefix(hostedZoneID, "/hostedzone/") { - hostedZoneID = strings.TrimPrefix(hostedZoneID, "/hostedzone/") - } - - return hostedZoneID, nil -} - -func newTXTRecordSet(fqdn, value string, ttl int) *route53.ResourceRecordSet { - return &route53.ResourceRecordSet{ - Name: aws.String(fqdn), - Type: aws.String("TXT"), - TTL: aws.Int64(int64(ttl)), - ResourceRecords: []*route53.ResourceRecord{ - {Value: aws.String(value)}, - }, - } -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/route53/route53_integration_test.go b/vendor/github.com/xenolf/lego/providers/dns/route53/route53_integration_test.go deleted file mode 100644 index 17ba4a08a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/route53/route53_integration_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package route53 - -import ( - "fmt" - "os" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53" -) - -func TestRoute53TTL(t *testing.T) { - - m, err := testGetAndPreCheck() - if err != nil { - t.Skip(err.Error()) - } - - provider, err := NewDNSProvider() - if err != nil { - t.Fatalf("Fatal: %s", err.Error()) - } - - err = provider.Present(m["route53Domain"], "foo", "bar") - if err != nil { - t.Fatalf("Fatal: %s", err.Error()) - } - // we need a separate R53 client here as the one in the DNS provider is - // unexported. - fqdn := "_acme-challenge." + m["route53Domain"] + "." - svc := route53.New(session.New()) - zoneID, err := provider.getHostedZoneID(fqdn) - if err != nil { - provider.CleanUp(m["route53Domain"], "foo", "bar") - t.Fatalf("Fatal: %s", err.Error()) - } - params := &route53.ListResourceRecordSetsInput{ - HostedZoneId: aws.String(zoneID), - } - resp, err := svc.ListResourceRecordSets(params) - if err != nil { - provider.CleanUp(m["route53Domain"], "foo", "bar") - t.Fatalf("Fatal: %s", err.Error()) - } - - for _, v := range resp.ResourceRecordSets { - if *v.Name == fqdn && *v.Type == "TXT" && *v.TTL == 10 { - provider.CleanUp(m["route53Domain"], "foo", "bar") - return - } - } - provider.CleanUp(m["route53Domain"], "foo", "bar") - t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", m["route53Domain"]) -} - -func testGetAndPreCheck() (map[string]string, error) { - m := map[string]string{ - "route53Key": os.Getenv("AWS_ACCESS_KEY_ID"), - "route53Secret": os.Getenv("AWS_SECRET_ACCESS_KEY"), - "route53Region": os.Getenv("AWS_REGION"), - "route53Domain": os.Getenv("R53_DOMAIN"), - } - for _, v := range m { - if v == "" { - return nil, fmt.Errorf("AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, and R53_DOMAIN are needed to run this test") - } - } - return m, nil -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/route53/route53_test.go b/vendor/github.com/xenolf/lego/providers/dns/route53/route53_test.go deleted file mode 100644 index de4e28f3d..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/route53/route53_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package route53 - -import ( - "net/http/httptest" - "os" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/stretchr/testify/assert" -) - -var ( - route53Secret string - route53Key string - route53Region string - route53Zone string -) - -func init() { - route53Key = os.Getenv("AWS_ACCESS_KEY_ID") - route53Secret = os.Getenv("AWS_SECRET_ACCESS_KEY") - route53Region = os.Getenv("AWS_REGION") - route53Zone = os.Getenv("AWS_HOSTED_ZONE_ID") -} - -func restoreRoute53Env() { - os.Setenv("AWS_ACCESS_KEY_ID", route53Key) - os.Setenv("AWS_SECRET_ACCESS_KEY", route53Secret) - os.Setenv("AWS_REGION", route53Region) - os.Setenv("AWS_HOSTED_ZONE_ID", route53Zone) -} - -func makeRoute53Provider(ts *httptest.Server) *DNSProvider { - config := &aws.Config{ - Credentials: credentials.NewStaticCredentials("abc", "123", " "), - Endpoint: aws.String(ts.URL), - Region: aws.String("mock-region"), - MaxRetries: aws.Int(1), - } - - client := route53.New(session.New(config)) - return &DNSProvider{client: client} -} - -func TestCredentialsFromEnv(t *testing.T) { - os.Setenv("AWS_ACCESS_KEY_ID", "123") - os.Setenv("AWS_SECRET_ACCESS_KEY", "123") - os.Setenv("AWS_REGION", "us-east-1") - - config := &aws.Config{ - CredentialsChainVerboseErrors: aws.Bool(true), - } - - sess := session.New(config) - _, err := sess.Config.Credentials.Get() - assert.NoError(t, err, "Expected credentials to be set from environment") - - restoreRoute53Env() -} - -func TestRegionFromEnv(t *testing.T) { - os.Setenv("AWS_REGION", "us-east-1") - - sess := session.New(aws.NewConfig()) - assert.Equal(t, "us-east-1", *sess.Config.Region, "Expected Region to be set from environment") - - restoreRoute53Env() -} - -func TestHostedZoneIDFromEnv(t *testing.T) { - const testZoneID = "testzoneid" - - defer restoreRoute53Env() - os.Setenv("AWS_HOSTED_ZONE_ID", testZoneID) - - provider, err := NewDNSProvider() - assert.NoError(t, err, "Expected no error constructing DNSProvider") - - fqdn, err := provider.getHostedZoneID("whatever") - assert.NoError(t, err, "Expected FQDN to be resolved to environment variable value") - - assert.Equal(t, testZoneID, fqdn) -} - -func TestRoute53Present(t *testing.T) { - mockResponses := MockResponseMap{ - "/2013-04-01/hostedzonesbyname": MockResponse{StatusCode: 200, Body: ListHostedZonesByNameResponse}, - "/2013-04-01/hostedzone/ABCDEFG/rrset/": MockResponse{StatusCode: 200, Body: ChangeResourceRecordSetsResponse}, - "/2013-04-01/change/123456": MockResponse{StatusCode: 200, Body: GetChangeResponse}, - } - - ts := newMockServer(t, mockResponses) - defer ts.Close() - - provider := makeRoute53Provider(ts) - - domain := "example.com" - keyAuth := "123456d==" - - err := provider.Present(domain, "", keyAuth) - assert.NoError(t, err, "Expected Present to return no error") -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/route53/testutil_test.go b/vendor/github.com/xenolf/lego/providers/dns/route53/testutil_test.go deleted file mode 100644 index e448a6858..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/route53/testutil_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package route53 - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/stretchr/testify/require" -) - -// MockResponse represents a predefined response used by a mock server -type MockResponse struct { - StatusCode int - Body string -} - -// MockResponseMap maps request paths to responses -type MockResponseMap map[string]MockResponse - -func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path - resp, ok := responses[path] - if !ok { - msg := fmt.Sprintf("Requested path not found in response map: %s", path) - require.FailNow(t, msg) - } - - w.Header().Set("Content-Type", "application/xml") - w.WriteHeader(resp.StatusCode) - w.Write([]byte(resp.Body)) - })) - - time.Sleep(100 * time.Millisecond) - return ts -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go b/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go deleted file mode 100644 index bc2067579..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go +++ /dev/null @@ -1,127 +0,0 @@ -// Package vultr implements a DNS provider for solving the DNS-01 challenge using -// the vultr DNS. -// See https://www.vultr.com/api/#dns -package vultr - -import ( - "fmt" - "os" - "strings" - - vultr "github.com/JamesClonk/vultr/lib" - "github.com/xenolf/lego/acme" -) - -// DNSProvider is an implementation of the acme.ChallengeProvider interface. -type DNSProvider struct { - client *vultr.Client -} - -// NewDNSProvider returns a DNSProvider instance with a configured Vultr client. -// Authentication uses the VULTR_API_KEY environment variable. -func NewDNSProvider() (*DNSProvider, error) { - apiKey := os.Getenv("VULTR_API_KEY") - return NewDNSProviderCredentials(apiKey) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a DNSProvider -// instance configured for Vultr. -func NewDNSProviderCredentials(apiKey string) (*DNSProvider, error) { - if apiKey == "" { - return nil, fmt.Errorf("Vultr credentials missing") - } - - c := &DNSProvider{ - client: vultr.NewClient(apiKey, nil), - } - - return c, nil -} - -// 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) - - zoneDomain, err := c.getHostedZone(domain) - if err != nil { - return err - } - - name := c.extractRecordName(fqdn, zoneDomain) - - err = c.client.CreateDNSRecord(zoneDomain, name, "TXT", `"`+value+`"`, 0, ttl) - if err != nil { - return fmt.Errorf("Vultr API call failed: %v", err) - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters. -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - - zoneDomain, records, err := c.findTxtRecords(domain, fqdn) - if err != nil { - return err - } - - for _, rec := range records { - err := c.client.DeleteDNSRecord(zoneDomain, rec.RecordID) - if err != nil { - return err - } - } - return nil -} - -func (c *DNSProvider) getHostedZone(domain string) (string, error) { - domains, err := c.client.GetDNSDomains() - if err != nil { - return "", fmt.Errorf("Vultr API call failed: %v", err) - } - - var hostedDomain vultr.DNSDomain - for _, d := range domains { - if strings.HasSuffix(domain, d.Domain) { - if len(d.Domain) > len(hostedDomain.Domain) { - hostedDomain = d - } - } - } - if hostedDomain.Domain == "" { - return "", fmt.Errorf("No matching Vultr domain found for domain %s", domain) - } - - return hostedDomain.Domain, nil -} - -func (c *DNSProvider) findTxtRecords(domain, fqdn string) (string, []vultr.DNSRecord, error) { - zoneDomain, err := c.getHostedZone(domain) - if err != nil { - return "", nil, err - } - - var records []vultr.DNSRecord - result, err := c.client.GetDNSRecords(zoneDomain) - if err != nil { - return "", records, fmt.Errorf("Vultr API call has failed: %v", err) - } - - recordName := c.extractRecordName(fqdn, zoneDomain) - for _, record := range result { - if record.Type == "TXT" && record.Name == recordName { - records = append(records, record) - } - } - - return zoneDomain, records, nil -} - -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 -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr_test.go b/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr_test.go deleted file mode 100644 index 7c8cdaf1e..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/vultr/vultr_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package vultr - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - liveTest bool - apiKey string - domain string -) - -func init() { - apiKey = os.Getenv("VULTR_API_KEY") - domain = os.Getenv("VULTR_TEST_DOMAIN") - liveTest = len(apiKey) > 0 && len(domain) > 0 -} - -func restoreEnv() { - os.Setenv("VULTR_API_KEY", apiKey) -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - os.Setenv("VULTR_API_KEY", "123") - defer restoreEnv() - _, err := NewDNSProvider() - assert.NoError(t, err) -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - os.Setenv("VULTR_API_KEY", "") - defer restoreEnv() - _, err := NewDNSProvider() - assert.EqualError(t, err, "Vultr credentials missing") -} - -func TestLivePresent(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(domain, "", "123d==") - assert.NoError(t, err) -} - -func TestLiveCleanUp(t *testing.T) { - if !liveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 1) - - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(domain, "", "123d==") - assert.NoError(t, err) -} -- cgit v1.2.3-1-g7c22