ACME DNS challenges
This commit is contained in:
parent
7a2592b2fa
commit
5bdf8a5ea3
127 changed files with 24386 additions and 739 deletions
37
vendor/github.com/xenolf/lego/acme/client.go
generated
vendored
37
vendor/github.com/xenolf/lego/acme/client.go
generated
vendored
|
@ -26,6 +26,9 @@ const (
|
|||
// “new-reg”, “new-authz” and “new-cert” endpoints. From the documentation the
|
||||
// limitation is 20 requests per second, but using 20 as value doesn't work but 18 do
|
||||
overallRequestLimit = 18
|
||||
|
||||
statusValid = "valid"
|
||||
statusInvalid = "invalid"
|
||||
)
|
||||
|
||||
// User interface is to be implemented by users of this library.
|
||||
|
@ -43,7 +46,7 @@ type solver interface {
|
|||
|
||||
// Interface for challenges like dns, where we can set a record in advance for ALL challenges.
|
||||
// This saves quite a bit of time vs creating the records and solving them serially.
|
||||
type presolver interface {
|
||||
type preSolver interface {
|
||||
PreSolve(challenge challenge, domain string) error
|
||||
}
|
||||
|
||||
|
@ -502,9 +505,9 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
|
|||
// Start by checking to see if the certificate was based off a CSR, and
|
||||
// use that if it's defined.
|
||||
if len(cert.CSR) > 0 {
|
||||
csr, err := pemDecodeTox509CSR(cert.CSR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
csr, errP := pemDecodeTox509CSR(cert.CSR)
|
||||
if errP != nil {
|
||||
return nil, errP
|
||||
}
|
||||
newCert, failures := c.ObtainCertificateForCSR(*csr, bundle)
|
||||
return newCert, failures
|
||||
|
@ -537,7 +540,6 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
|
|||
}
|
||||
|
||||
func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, error) {
|
||||
|
||||
var identifiers []identifier
|
||||
for _, domain := range domains {
|
||||
identifiers = append(identifiers, identifier{Type: "dns", Value: domain})
|
||||
|
@ -577,16 +579,16 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
|
|||
|
||||
// loop through the resources, basically through the domains. First pass just selects a solver for each authz.
|
||||
for _, authz := range authorizations {
|
||||
if authz.Status == "valid" {
|
||||
if authz.Status == statusValid {
|
||||
// Boulder might recycle recent validated authz (see issue #267)
|
||||
log.Infof("[%s] acme: Authorization already valid; skipping challenge", authz.Identifier.Value)
|
||||
continue
|
||||
}
|
||||
if i, solver := c.chooseSolver(authz, authz.Identifier.Value); solver != nil {
|
||||
if i, solvr := c.chooseSolver(authz, authz.Identifier.Value); solvr != nil {
|
||||
authSolvers = append(authSolvers, &selectedAuthSolver{
|
||||
authz: authz,
|
||||
challengeIndex: i,
|
||||
solver: solver,
|
||||
solver: solvr,
|
||||
})
|
||||
} else {
|
||||
failures[authz.Identifier.Value] = fmt.Errorf("[%s] acme: Could not determine solvers", authz.Identifier.Value)
|
||||
|
@ -597,7 +599,7 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
|
|||
for _, item := range authSolvers {
|
||||
authz := item.authz
|
||||
i := item.challengeIndex
|
||||
if presolver, ok := item.solver.(presolver); ok {
|
||||
if presolver, ok := item.solver.(preSolver); ok {
|
||||
if err := presolver.PreSolve(authz.Challenges[i], authz.Identifier.Value); err != nil {
|
||||
failures[authz.Identifier.Value] = err
|
||||
}
|
||||
|
@ -607,12 +609,12 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
|
|||
defer func() {
|
||||
// clean all created TXT records
|
||||
for _, item := range authSolvers {
|
||||
if cleanup, ok := item.solver.(cleanup); ok {
|
||||
if clean, ok := item.solver.(cleanup); ok {
|
||||
if failures[item.authz.Identifier.Value] != nil {
|
||||
// already failed in previous loop
|
||||
continue
|
||||
}
|
||||
err := cleanup.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value)
|
||||
err := clean.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value)
|
||||
if err != nil {
|
||||
log.Warnf("Error cleaning up %s: %v ", item.authz.Identifier.Value, err)
|
||||
}
|
||||
|
@ -755,7 +757,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if retOrder.Status == "invalid" {
|
||||
if retOrder.Status == statusInvalid {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -765,7 +767,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
|
|||
PrivateKey: privateKeyPem,
|
||||
}
|
||||
|
||||
if retOrder.Status == "valid" {
|
||||
if retOrder.Status == statusValid {
|
||||
// if the certificate is available right away, short cut!
|
||||
ok, err := c.checkCertResponse(retOrder, &certRes, bundle)
|
||||
if err != nil {
|
||||
|
@ -809,9 +811,8 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
|
|||
// should already have the Domain (common name) field populated. If bundle is
|
||||
// true, the certificate will be bundled with the issuer's cert.
|
||||
func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) {
|
||||
|
||||
switch order.Status {
|
||||
case "valid":
|
||||
case statusValid:
|
||||
resp, err := httpGet(order.Certificate)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -860,7 +861,7 @@ func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResou
|
|||
|
||||
case "processing":
|
||||
return false, nil
|
||||
case "invalid":
|
||||
case statusInvalid:
|
||||
return false, errors.New("order has invalid state: invalid")
|
||||
default:
|
||||
return false, nil
|
||||
|
@ -922,12 +923,12 @@ func validate(j *jws, domain, uri string, c challenge) error {
|
|||
// Repeatedly check the server for an updated status on our request.
|
||||
for {
|
||||
switch chlng.Status {
|
||||
case "valid":
|
||||
case statusValid:
|
||||
log.Infof("[%s] The server validated our request", domain)
|
||||
return nil
|
||||
case "pending":
|
||||
case "processing":
|
||||
case "invalid":
|
||||
case statusInvalid:
|
||||
return handleChallengeError(chlng)
|
||||
default:
|
||||
return errors.New("the server returned an unexpected state")
|
||||
|
|
27
vendor/github.com/xenolf/lego/acme/crypto.go
generated
vendored
27
vendor/github.com/xenolf/lego/acme/crypto.go
generated
vendored
|
@ -81,20 +81,20 @@ func GetOCSPForCert(bundle []byte) ([]byte, *ocsp.Response, error) {
|
|||
return nil, nil, errors.New("no issuing certificate URL")
|
||||
}
|
||||
|
||||
resp, err := httpGet(issuedCert.IssuingCertificateURL[0])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
resp, errC := httpGet(issuedCert.IssuingCertificateURL[0])
|
||||
if errC != nil {
|
||||
return nil, nil, errC
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
issuerBytes, err := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
issuerBytes, errC := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
|
||||
if errC != nil {
|
||||
return nil, nil, errC
|
||||
}
|
||||
|
||||
issuerCert, err := x509.ParseCertificate(issuerBytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
issuerCert, errC := x509.ParseCertificate(issuerBytes)
|
||||
if errC != nil {
|
||||
return nil, nil, errC
|
||||
}
|
||||
|
||||
// Insert it into the slice on position 0
|
||||
|
@ -258,15 +258,6 @@ func pemDecode(data []byte) (*pem.Block, error) {
|
|||
return pemBlock, nil
|
||||
}
|
||||
|
||||
func pemDecodeTox509(pem []byte) (*x509.Certificate, error) {
|
||||
pemBlock, err := pemDecode(pem)
|
||||
if pemBlock == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x509.ParseCertificate(pemBlock.Bytes)
|
||||
}
|
||||
|
||||
func pemDecodeTox509CSR(pem []byte) (*x509.CertificateRequest, error) {
|
||||
pemBlock, err := pemDecode(pem)
|
||||
if pemBlock == nil {
|
||||
|
|
2
vendor/github.com/xenolf/lego/acme/dns_challenge.go
generated
vendored
2
vendor/github.com/xenolf/lego/acme/dns_challenge.go
generated
vendored
|
@ -196,7 +196,7 @@ func checkAuthoritativeNss(fqdn, value string, nameservers []string) (bool, erro
|
|||
}
|
||||
|
||||
if !found {
|
||||
return false, fmt.Errorf("NS %s did not return the expected TXT record", ns)
|
||||
return false, fmt.Errorf("NS %s did not return the expected TXT record [fqdn: %s]", ns, fqdn)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
16
vendor/github.com/xenolf/lego/acme/http.go
generated
vendored
16
vendor/github.com/xenolf/lego/acme/http.go
generated
vendored
|
@ -148,29 +148,25 @@ func getJSON(uri string, respBody interface{}) (http.Header, error) {
|
|||
func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, error) {
|
||||
jsonBytes, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to marshal network message")
|
||||
return nil, errors.New("failed to marshal network message")
|
||||
}
|
||||
|
||||
resp, err := j.post(uri, jsonBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to post JWS message. -> %v", err)
|
||||
return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
|
||||
err := handleHTTPError(resp)
|
||||
|
||||
err = handleHTTPError(resp)
|
||||
switch err.(type) {
|
||||
|
||||
case NonceError:
|
||||
|
||||
// Retry once if the nonce was invalidated
|
||||
|
||||
retryResp, err := j.post(uri, jsonBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to post JWS message. -> %v", err)
|
||||
retryResp, errP := j.post(uri, jsonBytes)
|
||||
if errP != nil {
|
||||
return nil, fmt.Errorf("failed to post JWS message. -> %v", errP)
|
||||
}
|
||||
|
||||
defer retryResp.Body.Close()
|
||||
|
|
25
vendor/github.com/xenolf/lego/acme/http_challenge_server.go
generated
vendored
25
vendor/github.com/xenolf/lego/acme/http_challenge_server.go
generated
vendored
|
@ -35,7 +35,7 @@ func (s *HTTPProviderServer) Present(domain, token, keyAuth string) error {
|
|||
var err error
|
||||
s.listener, err = net.Listen("tcp", net.JoinHostPort(s.iface, s.port))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not start HTTP server for challenge -> %v", err)
|
||||
return fmt.Errorf("could not start HTTP server for challenge -> %v", err)
|
||||
}
|
||||
|
||||
s.done = make(chan bool)
|
||||
|
@ -62,20 +62,31 @@ func (s *HTTPProviderServer) serve(domain, token, keyAuth string) {
|
|||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasPrefix(r.Host, domain) && r.Method == http.MethodGet {
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
w.Write([]byte(keyAuth))
|
||||
_, err := w.Write([]byte(keyAuth))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Infof("[%s] Served key authentication", domain)
|
||||
} else {
|
||||
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the HOST header properly.", r.Host, r.Method)
|
||||
w.Write([]byte("TEST"))
|
||||
_, err := w.Write([]byte("TEST"))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
httpServer := &http.Server{
|
||||
Handler: mux,
|
||||
}
|
||||
httpServer := &http.Server{Handler: mux}
|
||||
|
||||
// Once httpServer is shut down we don't want any lingering
|
||||
// connections, so disable KeepAlives.
|
||||
httpServer.SetKeepAlivesEnabled(false)
|
||||
httpServer.Serve(s.listener)
|
||||
|
||||
err := httpServer.Serve(s.listener)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
s.done <- true
|
||||
}
|
||||
|
|
6
vendor/github.com/xenolf/lego/acme/tls_alpn_challenge_server.go
generated
vendored
6
vendor/github.com/xenolf/lego/acme/tls_alpn_challenge_server.go
generated
vendored
|
@ -3,6 +3,7 @@ package acme
|
|||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -65,7 +66,10 @@ func (t *TLSALPNProviderServer) Present(domain, token, keyAuth string) error {
|
|||
|
||||
// Shut the server down when we're finished.
|
||||
go func() {
|
||||
http.Serve(t.listener, nil)
|
||||
err := http.Serve(t.listener, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
|
|
10
vendor/github.com/xenolf/lego/acme/utils.go
generated
vendored
10
vendor/github.com/xenolf/lego/acme/utils.go
generated
vendored
|
@ -3,16 +3,20 @@ package acme
|
|||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xenolf/lego/log"
|
||||
)
|
||||
|
||||
// WaitFor polls the given function 'f', once every 'interval', up to 'timeout'.
|
||||
func WaitFor(timeout, interval time.Duration, f func() (bool, error)) error {
|
||||
log.Infof("Wait [timeout: %s, interval: %s]", timeout, interval)
|
||||
|
||||
var lastErr string
|
||||
timeup := time.After(timeout)
|
||||
timeUp := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-timeup:
|
||||
return fmt.Errorf("Time limit exceeded. Last error: %s", lastErr)
|
||||
case <-timeUp:
|
||||
return fmt.Errorf("time limit exceeded: last error: %s", lastErr)
|
||||
default:
|
||||
}
|
||||
|
||||
|
|
98
vendor/github.com/xenolf/lego/platform/config/env/env.go
generated
vendored
98
vendor/github.com/xenolf/lego/platform/config/env/env.go
generated
vendored
|
@ -1,11 +1,15 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xenolf/lego/log"
|
||||
)
|
||||
|
||||
// Get environment variables
|
||||
|
@ -14,7 +18,7 @@ func Get(names ...string) (map[string]string, error) {
|
|||
|
||||
var missingEnvVars []string
|
||||
for _, envVar := range names {
|
||||
value := os.Getenv(envVar)
|
||||
value := GetOrFile(envVar)
|
||||
if value == "" {
|
||||
missingEnvVars = append(missingEnvVars, envVar)
|
||||
}
|
||||
|
@ -28,10 +32,72 @@ func Get(names ...string) (map[string]string, error) {
|
|||
return values, nil
|
||||
}
|
||||
|
||||
// GetWithFallback Get environment variable values
|
||||
// The first name in each group is use as key in the result map
|
||||
//
|
||||
// // LEGO_ONE="ONE"
|
||||
// // LEGO_TWO="TWO"
|
||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||
// // => "LEGO_ONE" = "ONE"
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// // LEGO_ONE=""
|
||||
// // LEGO_TWO="TWO"
|
||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||
// // => "LEGO_ONE" = "TWO"
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// // LEGO_ONE=""
|
||||
// // LEGO_TWO=""
|
||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||
// // => error
|
||||
//
|
||||
func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
||||
values := map[string]string{}
|
||||
|
||||
var missingEnvVars []string
|
||||
for _, names := range groups {
|
||||
if len(names) == 0 {
|
||||
return nil, errors.New("undefined environment variable names")
|
||||
}
|
||||
|
||||
value, envVar := getOneWithFallback(names[0], names[1:]...)
|
||||
if len(value) == 0 {
|
||||
missingEnvVars = append(missingEnvVars, envVar)
|
||||
continue
|
||||
}
|
||||
values[envVar] = value
|
||||
}
|
||||
|
||||
if len(missingEnvVars) > 0 {
|
||||
return nil, fmt.Errorf("some credentials information are missing: %s", strings.Join(missingEnvVars, ","))
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func getOneWithFallback(main string, names ...string) (string, string) {
|
||||
value := GetOrFile(main)
|
||||
if len(value) > 0 {
|
||||
return value, main
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
value := GetOrFile(name)
|
||||
if len(value) > 0 {
|
||||
return value, main
|
||||
}
|
||||
}
|
||||
|
||||
return "", main
|
||||
}
|
||||
|
||||
// GetOrDefaultInt returns the given environment variable value as an integer.
|
||||
// Returns the default if the envvar cannot be coopered to an int, or is not found.
|
||||
func GetOrDefaultInt(envVar string, defaultValue int) int {
|
||||
v, err := strconv.Atoi(os.Getenv(envVar))
|
||||
v, err := strconv.Atoi(GetOrFile(envVar))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
@ -53,7 +119,7 @@ func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration
|
|||
// GetOrDefaultString returns the given environment variable value as a string.
|
||||
// Returns the default if the envvar cannot be find.
|
||||
func GetOrDefaultString(envVar string, defaultValue string) string {
|
||||
v := os.Getenv(envVar)
|
||||
v := GetOrFile(envVar)
|
||||
if len(v) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
|
@ -64,10 +130,34 @@ func GetOrDefaultString(envVar string, defaultValue string) string {
|
|||
// GetOrDefaultBool returns the given environment variable value as a boolean.
|
||||
// Returns the default if the envvar cannot be coopered to a boolean, or is not found.
|
||||
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
|
||||
v, err := strconv.ParseBool(os.Getenv(envVar))
|
||||
v, err := strconv.ParseBool(GetOrFile(envVar))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// GetOrFile Attempts to resolve 'key' as an environment variable.
|
||||
// Failing that, it will check to see if '<key>_FILE' exists.
|
||||
// If so, it will attempt to read from the referenced file to populate a value.
|
||||
func GetOrFile(envVar string) string {
|
||||
envVarValue := os.Getenv(envVar)
|
||||
if envVarValue != "" {
|
||||
return envVarValue
|
||||
}
|
||||
|
||||
fileVar := envVar + "_FILE"
|
||||
fileVarValue := os.Getenv(fileVar)
|
||||
if fileVarValue == "" {
|
||||
return envVarValue
|
||||
}
|
||||
|
||||
fileContents, err := ioutil.ReadFile(fileVarValue)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, fileVar, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(fileContents)
|
||||
}
|
||||
|
|
7
vendor/github.com/xenolf/lego/providers/dns/acmedns/acmedns.go
generated
vendored
7
vendor/github.com/xenolf/lego/providers/dns/acmedns/acmedns.go
generated
vendored
|
@ -1,6 +1,5 @@
|
|||
// Package acmedns implements a DNS provider for solving DNS-01 challenges using
|
||||
// Joohoi's acme-dns project. For more information see the ACME-DNS homepage:
|
||||
// https://github.com/joohoi/acme-dns
|
||||
// Package acmedns implements a DNS provider for solving DNS-01 challenges using Joohoi's acme-dns project.
|
||||
// For more information see the ACME-DNS homepage: https://github.com/joohoi/acme-dns
|
||||
package acmedns
|
||||
|
||||
import (
|
||||
|
@ -101,7 +100,7 @@ func (e ErrCNAMERequired) Error() string {
|
|||
e.Domain, e.Domain, e.FQDN, e.Target)
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the DNS-01 challenge. If there is an
|
||||
// Present creates a TXT record to fulfill the DNS-01 challenge. If there is an
|
||||
// existing account for the domain in the provider's storage then it will be
|
||||
// used to set the challenge response TXT record with the ACME-DNS server and
|
||||
// issuance will continue. If there is not an account for the given domain
|
||||
|
|
5
vendor/github.com/xenolf/lego/providers/dns/alidns/alidns.go
generated
vendored
5
vendor/github.com/xenolf/lego/providers/dns/alidns/alidns.go
generated
vendored
|
@ -5,7 +5,6 @@ package alidns
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -57,7 +56,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
config := NewDefaultConfig()
|
||||
config.APIKey = values["ALICLOUD_ACCESS_KEY"]
|
||||
config.SecretKey = values["ALICLOUD_SECRET_KEY"]
|
||||
config.RegionID = os.Getenv("ALICLOUD_REGION_ID")
|
||||
config.RegionID = env.GetOrFile("ALICLOUD_REGION_ID")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
@ -105,7 +104,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
3
vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go
generated
vendored
3
vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go
generated
vendored
|
@ -3,7 +3,6 @@ package auroradns
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -53,7 +52,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.BaseURL = os.Getenv("AURORA_ENDPOINT")
|
||||
config.BaseURL = env.GetOrFile("AURORA_ENDPOINT")
|
||||
config.UserID = values["AURORA_USER_ID"]
|
||||
config.Key = values["AURORA_KEY"]
|
||||
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/azure/azure.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/azure/azure.go
generated
vendored
|
@ -99,7 +99,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
ctx := context.Background()
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/bluecat/bluecat.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/bluecat/bluecat.go
generated
vendored
|
@ -353,7 +353,7 @@ func (d *DNSProvider) lookupViewID(viewName string) (uint, error) {
|
|||
|
||||
queryArgs := map[string]string{
|
||||
"parentId": strconv.FormatUint(uint64(confID), 10),
|
||||
"name": d.config.DNSView,
|
||||
"name": viewName,
|
||||
"type": viewType,
|
||||
}
|
||||
|
||||
|
|
212
vendor/github.com/xenolf/lego/providers/dns/cloudflare/client.go
generated
vendored
212
vendor/github.com/xenolf/lego/providers/dns/cloudflare/client.go
generated
vendored
|
@ -1,212 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/xenolf/lego/acme"
|
||||
)
|
||||
|
||||
// defaultBaseURL represents the API endpoint to call.
|
||||
const defaultBaseURL = "https://api.cloudflare.com/client/v4"
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// TxtRecord represents a Cloudflare DNS record
|
||||
type TxtRecord 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"`
|
||||
}
|
||||
|
||||
// HostedZone represents a Cloudflare DNS zone
|
||||
type HostedZone struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Client Cloudflare API client
|
||||
type Client struct {
|
||||
authEmail string
|
||||
authKey string
|
||||
BaseURL string
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient create a Cloudflare API client
|
||||
func NewClient(authEmail string, authKey string) (*Client, error) {
|
||||
if authEmail == "" {
|
||||
return nil, errors.New("cloudflare: some credentials information are missing: email")
|
||||
}
|
||||
|
||||
if authKey == "" {
|
||||
return nil, errors.New("cloudflare: some credentials information are missing: key")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
authEmail: authEmail,
|
||||
authKey: authKey,
|
||||
BaseURL: defaultBaseURL,
|
||||
HTTPClient: http.DefaultClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetHostedZoneID get hosted zone
|
||||
func (c *Client) GetHostedZoneID(fqdn string) (string, error) {
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
result, err := c.doRequest(http.MethodGet, "/zones?name="+acme.UnFqdn(authZone), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var hostedZone []HostedZone
|
||||
err = json.Unmarshal(result, &hostedZone)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cloudflare: HostedZone unmarshaling error: %v", err)
|
||||
}
|
||||
|
||||
count := len(hostedZone)
|
||||
if count == 0 {
|
||||
return "", fmt.Errorf("cloudflare: zone %s not found for domain %s", authZone, fqdn)
|
||||
} else if count > 1 {
|
||||
return "", fmt.Errorf("cloudflare: zone %s cannot be find for domain %s: too many hostedZone: %v", authZone, fqdn, hostedZone)
|
||||
}
|
||||
|
||||
return hostedZone[0].ID, nil
|
||||
}
|
||||
|
||||
// FindTxtRecord Find a TXT record
|
||||
func (c *Client) FindTxtRecord(zoneID, fqdn string) (*TxtRecord, error) {
|
||||
result, err := c.doRequest(
|
||||
http.MethodGet,
|
||||
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 []TxtRecord
|
||||
err = json.Unmarshal(result, &records)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: record unmarshaling error: %v", err)
|
||||
}
|
||||
|
||||
for _, rec := range records {
|
||||
fmt.Println(rec.Name, acme.UnFqdn(fqdn))
|
||||
if rec.Name == acme.UnFqdn(fqdn) {
|
||||
return &rec, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cloudflare: no existing record found for %s", fqdn)
|
||||
}
|
||||
|
||||
// AddTxtRecord add a TXT record
|
||||
func (c *Client) AddTxtRecord(fqdn string, record TxtRecord) error {
|
||||
zoneID, err := c.GetHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: record marshaling error: %v", err)
|
||||
}
|
||||
|
||||
_, err = c.doRequest(http.MethodPost, fmt.Sprintf("/zones/%s/dns_records", zoneID), bytes.NewReader(body))
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveTxtRecord Remove a TXT record
|
||||
func (c *Client) RemoveTxtRecord(fqdn string) error {
|
||||
zoneID, err := c.GetHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record, err := c.FindTxtRecord(zoneID, fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.doRequest(http.MethodDelete, fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
|
||||
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", c.BaseURL, uri), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("X-Auth-Email", c.authEmail)
|
||||
req.Header.Set("X-Auth-Key", c.authKey)
|
||||
|
||||
resp, err := c.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: error querying API: %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: %s", toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
var r APIResponse
|
||||
err = json.Unmarshal(content, &r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: APIResponse unmarshaling error: %v: %s", err, toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
if !r.Success {
|
||||
if len(r.Errors) > 0 {
|
||||
return nil, fmt.Errorf("cloudflare: error \n%s", toError(r))
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cloudflare: %s", toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
func toUnreadableBodyMessage(req *http.Request, rawBody []byte) string {
|
||||
return fmt.Sprintf("the request %s sent a response with a body which is an invalid format: %q", req.URL, string(rawBody))
|
||||
}
|
||||
|
||||
func toError(r APIResponse) error {
|
||||
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 fmt.Errorf("cloudflare: error \n%s", errStr)
|
||||
}
|
89
vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go
generated
vendored
89
vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go
generated
vendored
|
@ -8,12 +8,18 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/log"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
)
|
||||
|
||||
// CloudFlareAPIURL represents the API endpoint to call.
|
||||
const CloudFlareAPIURL = defaultBaseURL // Deprecated
|
||||
const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4" // Deprecated
|
||||
|
||||
const (
|
||||
minTTL = 120
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
|
@ -28,7 +34,7 @@ type Config struct {
|
|||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: env.GetOrDefaultInt("CLOUDFLARE_TTL", 120),
|
||||
TTL: env.GetOrDefaultInt("CLOUDFLARE_TTL", minTTL),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("CLOUDFLARE_PROPAGATION_TIMEOUT", 2*time.Minute),
|
||||
PollingInterval: env.GetOrDefaultSecond("CLOUDFLARE_POLLING_INTERVAL", 2*time.Second),
|
||||
HTTPClient: &http.Client{
|
||||
|
@ -39,7 +45,7 @@ func NewDefaultConfig() *Config {
|
|||
|
||||
// DNSProvider is an implementation of the acme.ChallengeProvider interface
|
||||
type DNSProvider struct {
|
||||
client *Client
|
||||
client *cloudflare.API
|
||||
config *Config
|
||||
}
|
||||
|
||||
|
@ -47,7 +53,9 @@ type DNSProvider struct {
|
|||
// Credentials must be passed in the environment variables:
|
||||
// CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get("CLOUDFLARE_EMAIL", "CLOUDFLARE_API_KEY")
|
||||
values, err := env.GetWithFallback(
|
||||
[]string{"CLOUDFLARE_EMAIL", "CF_API_EMAIL"},
|
||||
[]string{"CLOUDFLARE_API_KEY", "CF_API_KEY"})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
@ -76,45 +84,92 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("cloudflare: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
client, err := NewClient(config.AuthEmail, config.AuthKey)
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("cloudflare: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
client, err := cloudflare.New(config.AuthKey, config.AuthEmail, cloudflare.HTTPClient(config.HTTPClient))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.HTTPClient = config.HTTPClient
|
||||
|
||||
// TODO: must be remove. keep only for compatibility reason.
|
||||
client.BaseURL = CloudFlareAPIURL
|
||||
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
config: config,
|
||||
}, nil
|
||||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS
|
||||
// propagation. Adjusting here to cope with spikes in propagation times.
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
// Adjusting here to cope with spikes in propagation times.
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
rec := TxtRecord{
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
||||
dnsRecord := cloudflare.DNSRecord{
|
||||
Type: "TXT",
|
||||
Name: acme.UnFqdn(fqdn),
|
||||
Content: value,
|
||||
TTL: d.config.TTL,
|
||||
}
|
||||
|
||||
return d.client.AddTxtRecord(fqdn, rec)
|
||||
response, _ := d.client.CreateDNSRecord(zoneID, dnsRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to create TXT record: %v", err)
|
||||
}
|
||||
|
||||
if !response.Success {
|
||||
return fmt.Errorf("cloudflare: failed to create TXT record: %+v %+v", response.Errors, response.Messages)
|
||||
}
|
||||
|
||||
log.Infof("cloudflare: new record for %s, ID %s", domain, response.Result.ID)
|
||||
|
||||
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)
|
||||
|
||||
return d.client.RemoveTxtRecord(fqdn)
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
||||
dnsRecord := cloudflare.DNSRecord{
|
||||
Type: "TXT",
|
||||
Name: acme.UnFqdn(fqdn),
|
||||
}
|
||||
|
||||
records, err := d.client.DNSRecords(zoneID, dnsRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find TXT records: %v", err)
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
err = d.client.DeleteDNSRecord(zoneID, record.ID)
|
||||
if err != nil {
|
||||
log.Printf("cloudflare: failed to delete TXT record: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
6
vendor/github.com/xenolf/lego/providers/dns/cloudxns/cloudxns.go
generated
vendored
6
vendor/github.com/xenolf/lego/providers/dns/cloudxns/cloudxns.go
generated
vendored
|
@ -28,8 +28,8 @@ func NewDefaultConfig() *Config {
|
|||
client.Timeout = time.Second * time.Duration(env.GetOrDefaultInt("CLOUDXNS_HTTP_TIMEOUT", 30))
|
||||
|
||||
return &Config{
|
||||
PropagationTimeout: env.GetOrDefaultSecond("AKAMAI_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("AKAMAI_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("CLOUDXNS_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("CLOUDXNS_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
TTL: env.GetOrDefaultInt("CLOUDXNS_TTL", 120),
|
||||
HTTPClient: &client,
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
27
vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
generated
vendored
27
vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
generated
vendored
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/xenolf/lego/providers/dns/iij"
|
||||
"github.com/xenolf/lego/providers/dns/lightsail"
|
||||
"github.com/xenolf/lego/providers/dns/linode"
|
||||
"github.com/xenolf/lego/providers/dns/linodev4"
|
||||
"github.com/xenolf/lego/providers/dns/namecheap"
|
||||
"github.com/xenolf/lego/providers/dns/namedotcom"
|
||||
"github.com/xenolf/lego/providers/dns/netcup"
|
||||
|
@ -76,6 +77,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
|||
return dyn.NewDNSProvider()
|
||||
case "fastdns":
|
||||
return fastdns.NewDNSProvider()
|
||||
case "exec":
|
||||
return exec.NewDNSProvider()
|
||||
case "exoscale":
|
||||
return exoscale.NewDNSProvider()
|
||||
case "gandi":
|
||||
|
@ -96,6 +99,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
|||
return lightsail.NewDNSProvider()
|
||||
case "linode":
|
||||
return linode.NewDNSProvider()
|
||||
case "linodev4":
|
||||
return linodev4.NewDNSProvider()
|
||||
case "manual":
|
||||
return acme.NewDNSProviderManual()
|
||||
case "namecheap":
|
||||
|
@ -106,6 +111,14 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
|||
return netcup.NewDNSProvider()
|
||||
case "nifcloud":
|
||||
return nifcloud.NewDNSProvider()
|
||||
case "ns1":
|
||||
return ns1.NewDNSProvider()
|
||||
case "otc":
|
||||
return otc.NewDNSProvider()
|
||||
case "ovh":
|
||||
return ovh.NewDNSProvider()
|
||||
case "pdns":
|
||||
return pdns.NewDNSProvider()
|
||||
case "rackspace":
|
||||
return rackspace.NewDNSProvider()
|
||||
case "route53":
|
||||
|
@ -114,20 +127,10 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
|||
return rfc2136.NewDNSProvider()
|
||||
case "sakuracloud":
|
||||
return sakuracloud.NewDNSProvider()
|
||||
case "vultr":
|
||||
return vultr.NewDNSProvider()
|
||||
case "ovh":
|
||||
return ovh.NewDNSProvider()
|
||||
case "pdns":
|
||||
return pdns.NewDNSProvider()
|
||||
case "ns1":
|
||||
return ns1.NewDNSProvider()
|
||||
case "otc":
|
||||
return otc.NewDNSProvider()
|
||||
case "exec":
|
||||
return exec.NewDNSProvider()
|
||||
case "vegadns":
|
||||
return vegadns.NewDNSProvider()
|
||||
case "vultr":
|
||||
return vultr.NewDNSProvider()
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognised DNS provider: %s", name)
|
||||
}
|
||||
|
|
36
vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go
generated
vendored
36
vendor/github.com/xenolf/lego/providers/dns/dnsimple/dnsimple.go
generated
vendored
|
@ -5,7 +5,6 @@ package dnsimple
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -45,8 +44,8 @@ type DNSProvider struct {
|
|||
// See: https://developer.dnsimple.com/v2/#authentication
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
config := NewDefaultConfig()
|
||||
config.AccessToken = os.Getenv("DNSIMPLE_OAUTH_TOKEN")
|
||||
config.BaseURL = os.Getenv("DNSIMPLE_BASE_URL")
|
||||
config.AccessToken = env.GetOrFile("DNSIMPLE_OAUTH_TOKEN")
|
||||
config.BaseURL = env.GetOrFile("DNSIMPLE_BASE_URL")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
@ -79,27 +78,27 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
client.BaseURL = config.BaseURL
|
||||
}
|
||||
|
||||
return &DNSProvider{client: client}, nil
|
||||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
zoneName, err := d.getHostedZone(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("dnsimple: %v", err)
|
||||
}
|
||||
|
||||
accountID, err := d.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("dnsimple: %v", err)
|
||||
}
|
||||
|
||||
recordAttributes := d.newTxtRecord(zoneName, fqdn, value, d.config.TTL)
|
||||
recordAttributes := newTxtRecord(zoneName, fqdn, value, d.config.TTL)
|
||||
_, err = d.client.Zones.CreateRecord(accountID, zoneName, recordAttributes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("API call failed: %v", err)
|
||||
return fmt.Errorf("dnsimple: API call failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -111,22 +110,23 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
records, err := d.findTxtRecords(domain, fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("dnsimple: %v", err)
|
||||
}
|
||||
|
||||
accountID, err := d.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("dnsimple: %v", err)
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
for _, rec := range records {
|
||||
_, err := d.client.Zones.DeleteRecord(accountID, rec.ZoneID, rec.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
lastErr = fmt.Errorf("dnsimple: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
|
@ -178,18 +178,18 @@ func (d *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnsimple.ZoneRecord
|
|||
return nil, err
|
||||
}
|
||||
|
||||
recordName := d.extractRecordName(fqdn, zoneName)
|
||||
recordName := extractRecordName(fqdn, zoneName)
|
||||
|
||||
result, err := d.client.Zones.ListRecords(accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: recordName, Type: "TXT", ListOptions: dnsimple.ListOptions{}})
|
||||
if err != nil {
|
||||
return []dnsimple.ZoneRecord{}, fmt.Errorf("API call has failed: %v", err)
|
||||
return nil, fmt.Errorf("API call has failed: %v", err)
|
||||
}
|
||||
|
||||
return result.Data, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) newTxtRecord(zoneName, fqdn, value string, ttl int) dnsimple.ZoneRecord {
|
||||
name := d.extractRecordName(fqdn, zoneName)
|
||||
func newTxtRecord(zoneName, fqdn, value string, ttl int) dnsimple.ZoneRecord {
|
||||
name := extractRecordName(fqdn, zoneName)
|
||||
|
||||
return dnsimple.ZoneRecord{
|
||||
Type: "TXT",
|
||||
|
@ -199,7 +199,7 @@ func (d *DNSProvider) newTxtRecord(zoneName, fqdn, value string, ttl int) dnsimp
|
|||
}
|
||||
}
|
||||
|
||||
func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
|
||||
func extractRecordName(fqdn, domain string) string {
|
||||
name := acme.UnFqdn(fqdn)
|
||||
if idx := strings.Index(name, "."+domain); idx != -1 {
|
||||
return name[:idx]
|
||||
|
|
3
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go
generated
vendored
3
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go
generated
vendored
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -57,7 +56,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
}
|
||||
|
||||
var baseURL string
|
||||
if sandbox, _ := strconv.ParseBool(os.Getenv("DNSMADEEASY_SANDBOX")); sandbox {
|
||||
if sandbox, _ := strconv.ParseBool(env.GetOrFile("DNSMADEEASY_SANDBOX")); sandbox {
|
||||
baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0"
|
||||
} else {
|
||||
baseURL = "https://api.dnsmadeeasy.com/V2.0"
|
||||
|
|
6
vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go
generated
vendored
6
vendor/github.com/xenolf/lego/providers/dns/dnspod/dnspod.go
generated
vendored
|
@ -28,8 +28,8 @@ type Config struct {
|
|||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: env.GetOrDefaultInt("DNSPOD_TTL", 600),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("ALICLOUD_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("ALICLOUD_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("DNSPOD_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("DNSPOD_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
HTTPClient: &http.Client{
|
||||
Timeout: env.GetOrDefaultSecond("DNSPOD_HTTP_TIMEOUT", 0),
|
||||
},
|
||||
|
@ -84,7 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
zoneID, zoneName, err := d.getHostedZone(domain)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/duckdns/duckdns.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/duckdns/duckdns.go
generated
vendored
|
@ -75,7 +75,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
_, txtRecord, _ := acme.DNS01Record(domain, keyAuth)
|
||||
return updateTxtRecord(domain, d.config.Token, txtRecord, false)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/exec/exec.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/exec/exec.go
generated
vendored
|
@ -59,7 +59,7 @@ func NewDNSProviderProgram(program string) (*DNSProvider, error) {
|
|||
return NewDNSProviderConfig(&Config{Program: program})
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
var args []string
|
||||
if d.config.Mode == "RAW" {
|
||||
|
|
5
vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go
generated
vendored
5
vendor/github.com/xenolf/lego/providers/dns/exoscale/exoscale.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/exoscale/egoscale"
|
||||
|
@ -56,7 +55,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
config := NewDefaultConfig()
|
||||
config.APIKey = values["EXOSCALE_API_KEY"]
|
||||
config.APISecret = values["EXOSCALE_API_SECRET"]
|
||||
config.Endpoint = os.Getenv("EXOSCALE_ENDPOINT")
|
||||
config.Endpoint = env.GetOrFile("EXOSCALE_ENDPOINT")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
@ -93,7 +92,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
zone, recordName, err := d.FindZoneAndRecordName(fqdn, domain)
|
||||
|
|
14
vendor/github.com/xenolf/lego/providers/dns/fastdns/fastdns.go
generated
vendored
14
vendor/github.com/xenolf/lego/providers/dns/fastdns/fastdns.go
generated
vendored
|
@ -99,10 +99,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
record := configdns.NewTxtRecord()
|
||||
record.SetField("name", recordName)
|
||||
record.SetField("ttl", d.config.TTL)
|
||||
record.SetField("target", value)
|
||||
record.SetField("active", true)
|
||||
_ = record.SetField("name", recordName)
|
||||
_ = record.SetField("ttl", d.config.TTL)
|
||||
_ = record.SetField("target", value)
|
||||
_ = record.SetField("active", true)
|
||||
|
||||
existingRecord := d.findExistingRecord(zone, recordName)
|
||||
|
||||
|
@ -110,8 +110,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
if reflect.DeepEqual(existingRecord.ToMap(), record.ToMap()) {
|
||||
return nil
|
||||
}
|
||||
zone.RemoveRecord(existingRecord)
|
||||
return d.createRecord(zone, record)
|
||||
err = zone.RemoveRecord(existingRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fastdns: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return d.createRecord(zone, record)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/gandi/client.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/gandi/client.go
generated
vendored
|
@ -82,8 +82,6 @@ type responseBool struct {
|
|||
Value bool `xml:"params>param>value>boolean"`
|
||||
}
|
||||
|
||||
// POSTing/Marshalling/Unmarshalling
|
||||
|
||||
type rpcError struct {
|
||||
faultCode int
|
||||
faultString string
|
||||
|
|
6
vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go
generated
vendored
6
vendor/github.com/xenolf/lego/providers/dns/gandi/gandi.go
generated
vendored
|
@ -230,9 +230,9 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
}
|
||||
|
||||
// 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.
|
||||
// marshaling 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 (d *DNSProvider) rpcCall(call *methodCall, resp response) error {
|
||||
// marshal
|
||||
b, err := xml.MarshalIndent(call, "", " ")
|
||||
|
|
119
vendor/github.com/xenolf/lego/providers/dns/gandiv5/client.go
generated
vendored
119
vendor/github.com/xenolf/lego/providers/dns/gandiv5/client.go
generated
vendored
|
@ -1,18 +1,123 @@
|
|||
package gandiv5
|
||||
|
||||
// types for JSON method calls and parameters
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type addFieldRequest struct {
|
||||
const apiKeyHeader = "X-Api-Key"
|
||||
|
||||
// types for JSON responses with only a message
|
||||
type apiResponse struct {
|
||||
Message string `json:"message"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
}
|
||||
|
||||
// Record TXT record representation
|
||||
type Record struct {
|
||||
RRSetTTL int `json:"rrset_ttl"`
|
||||
RRSetValues []string `json:"rrset_values"`
|
||||
RRSetName string `json:"rrset_name,omitempty"`
|
||||
RRSetType string `json:"rrset_type,omitempty"`
|
||||
}
|
||||
|
||||
type deleteFieldRequest struct {
|
||||
Delete bool `json:"delete"`
|
||||
func (d *DNSProvider) newRequest(method, resource string, body interface{}) (*http.Request, error) {
|
||||
u := fmt.Sprintf("%s/%s", d.config.BaseURL, resource)
|
||||
|
||||
if body == nil {
|
||||
req, err := http.NewRequest(method, u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
reqBody, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u, bytes.NewBuffer(reqBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// types for JSON responses
|
||||
func (d *DNSProvider) do(req *http.Request, v interface{}) error {
|
||||
if len(d.config.APIKey) > 0 {
|
||||
req.Header.Set(apiKeyHeader, d.config.APIKey)
|
||||
}
|
||||
|
||||
type responseStruct struct {
|
||||
Message string `json:"message"`
|
||||
resp, err := d.config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = checkResponse(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
raw, err := readBody(resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read body: %v", err)
|
||||
}
|
||||
|
||||
if len(raw) > 0 {
|
||||
err = json.Unmarshal(raw, v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshaling error: %v: %s", err, string(raw))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkResponse(resp *http.Response) error {
|
||||
if resp.StatusCode == 404 && resp.Request.Method == http.MethodGet {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
data, err := readBody(resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d [%s] request failed: %v", resp.StatusCode, http.StatusText(resp.StatusCode), err)
|
||||
}
|
||||
|
||||
message := &apiResponse{}
|
||||
err = json.Unmarshal(data, message)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d [%s] request failed: %v: %s", resp.StatusCode, http.StatusText(resp.StatusCode), err, data)
|
||||
}
|
||||
return fmt.Errorf("%d [%s] request failed: %s", resp.StatusCode, http.StatusText(resp.StatusCode), message.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readBody(resp *http.Response) ([]byte, error) {
|
||||
if resp.Body == nil {
|
||||
return nil, fmt.Errorf("response body is nil")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
rawBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rawBody, nil
|
||||
}
|
||||
|
|
118
vendor/github.com/xenolf/lego/providers/dns/gandiv5/gandiv5.go
generated
vendored
118
vendor/github.com/xenolf/lego/providers/dns/gandiv5/gandiv5.go
generated
vendored
|
@ -3,8 +3,6 @@
|
|||
package gandiv5
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -184,61 +182,75 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
// functions to perform API actions
|
||||
|
||||
func (d *DNSProvider) addTXTRecord(domain string, name string, value string, ttl int) error {
|
||||
target := fmt.Sprintf("domains/%s/records/%s/TXT", domain, name)
|
||||
response, err := d.sendRequest(http.MethodPut, target, addFieldRequest{
|
||||
RRSetTTL: ttl,
|
||||
RRSetValues: []string{value},
|
||||
})
|
||||
if response != nil {
|
||||
log.Infof("gandiv5: %s", response.Message)
|
||||
// Get exiting values for the TXT records
|
||||
// Needed to create challenges for both wildcard and base name domains
|
||||
txtRecord, err := d.getTXTRecord(domain, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
|
||||
values := []string{value}
|
||||
if len(txtRecord.RRSetValues) > 0 {
|
||||
values = append(values, txtRecord.RRSetValues...)
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("domains/%s/records/%s/TXT", domain, name)
|
||||
|
||||
newRecord := &Record{RRSetTTL: ttl, RRSetValues: values}
|
||||
req, err := d.newRequest(http.MethodPut, target, newRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message := &apiResponse{}
|
||||
err = d.do(req, message)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create TXT record for domain %s and name %s: %v", domain, name, err)
|
||||
}
|
||||
|
||||
if message != nil && len(message.Message) > 0 {
|
||||
log.Infof("API response: %s", message.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getTXTRecord(domain, name string) (*Record, error) {
|
||||
target := fmt.Sprintf("domains/%s/records/%s/TXT", domain, name)
|
||||
|
||||
// Get exiting values for the TXT records
|
||||
// Needed to create challenges for both wildcard and base name domains
|
||||
req, err := d.newRequest(http.MethodGet, target, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txtRecord := &Record{}
|
||||
err = d.do(req, txtRecord)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get TXT records for domain %s and name %s: %v", domain, name, err)
|
||||
}
|
||||
|
||||
return txtRecord, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) deleteTXTRecord(domain string, name string) error {
|
||||
target := fmt.Sprintf("domains/%s/records/%s/TXT", domain, name)
|
||||
response, err := d.sendRequest(http.MethodDelete, target, deleteFieldRequest{
|
||||
Delete: true,
|
||||
})
|
||||
if response != nil && response.Message == "" {
|
||||
log.Infof("gandiv5: Zone record deleted")
|
||||
|
||||
req, err := d.newRequest(http.MethodDelete, target, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *DNSProvider) sendRequest(method string, resource string, payload interface{}) (*responseStruct, error) {
|
||||
url := fmt.Sprintf("%s/%s", d.config.BaseURL, 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.config.APIKey) > 0 {
|
||||
req.Header.Set("X-Api-Key", d.config.APIKey)
|
||||
}
|
||||
|
||||
resp, err := d.config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
return nil, fmt.Errorf("request failed with HTTP status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var response responseStruct
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
if err != nil && method != http.MethodDelete {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
|
||||
message := &apiResponse{}
|
||||
err = d.do(req, message)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to delete TXT record for domain %s and name %s: %v", domain, name, err)
|
||||
}
|
||||
|
||||
if message != nil && len(message.Message) > 0 {
|
||||
log.Infof("API response: %s", message.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go
generated
vendored
|
@ -122,7 +122,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{config: config, client: svc}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/glesys/glesys.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/glesys/glesys.go
generated
vendored
|
@ -160,8 +160,6 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// POSTing/Marshalling/Unmarshalling
|
||||
|
||||
func (d *DNSProvider) sendRequest(method string, resource string, payload interface{}) (*responseStruct, error) {
|
||||
url := fmt.Sprintf("%s/%s", defaultBaseURL, resource)
|
||||
|
||||
|
|
10
vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go
generated
vendored
10
vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go
generated
vendored
|
@ -86,6 +86,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("godaddy: credentials missing")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("godaddy: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
return &DNSProvider{config: config}, nil
|
||||
}
|
||||
|
||||
|
@ -103,7 +107,7 @@ func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
|
|||
return name
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
domainZone, err := d.getZone(fqdn)
|
||||
|
@ -111,10 +115,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if d.config.TTL < minTTL {
|
||||
d.config.TTL = minTTL
|
||||
}
|
||||
|
||||
recordName := d.extractRecordName(fqdn, domainZone)
|
||||
rec := []DNSRecord{
|
||||
{
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/hostingde/hostingde.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/hostingde/hostingde.go
generated
vendored
|
@ -89,7 +89,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
7
vendor/github.com/xenolf/lego/providers/dns/lightsail/lightsail.go
generated
vendored
7
vendor/github.com/xenolf/lego/providers/dns/lightsail/lightsail.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
@ -54,7 +53,7 @@ type Config struct {
|
|||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
DNSZone: os.Getenv("DNS_ZONE"),
|
||||
DNSZone: env.GetOrFile("DNS_ZONE"),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("LIGHTSAIL_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("LIGHTSAIL_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
Region: env.GetOrDefaultString("LIGHTSAIL_REGION", "us-east-1"),
|
||||
|
@ -108,7 +107,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
err := d.newTxtRecord(domain, fqdn, `"`+value+`"`)
|
||||
err := d.newTxtRecord(fqdn, `"`+value+`"`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("lightsail: %v", err)
|
||||
}
|
||||
|
@ -141,7 +140,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
func (d *DNSProvider) newTxtRecord(domain string, fqdn string, value string) error {
|
||||
func (d *DNSProvider) newTxtRecord(fqdn string, value string) error {
|
||||
params := &lightsail.CreateDomainEntryInput{
|
||||
DomainName: aws.String(d.config.DNSZone),
|
||||
DomainEntry: &lightsail.DomainEntry{
|
||||
|
|
13
vendor/github.com/xenolf/lego/providers/dns/linode/linode.go
generated
vendored
13
vendor/github.com/xenolf/lego/providers/dns/linode/linode.go
generated
vendored
|
@ -14,7 +14,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
dnsMinTTLSecs = 300
|
||||
minTTL = 300
|
||||
dnsUpdateFreqMins = 15
|
||||
dnsUpdateFudgeSecs = 120
|
||||
)
|
||||
|
@ -30,7 +30,7 @@ type Config struct {
|
|||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
PollingInterval: env.GetOrDefaultSecond("LINODE_POLLING_INTERVAL", 15*time.Second),
|
||||
TTL: env.GetOrDefaultInt("LINODE_TTL", 60),
|
||||
TTL: env.GetOrDefaultInt("LINODE_TTL", minTTL),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("linode: credentials missing")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("linode: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
client: dns.New(config.APIKey),
|
||||
|
@ -96,7 +100,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
minsRemaining := dnsUpdateFreqMins - (time.Now().Minute() % dnsUpdateFreqMins)
|
||||
|
||||
timeout = (time.Duration(minsRemaining) * time.Minute) +
|
||||
(dnsMinTTLSecs * time.Second) +
|
||||
(minTTL * time.Second) +
|
||||
(dnsUpdateFudgeSecs * time.Second)
|
||||
interval = d.config.PollingInterval
|
||||
return
|
||||
|
@ -110,7 +114,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if _, err = d.client.CreateDomainResourceTXT(zone.domainID, acme.UnFqdn(fqdn), value, 60); err != nil {
|
||||
if _, err = d.client.CreateDomainResourceTXT(zone.domainID, acme.UnFqdn(fqdn), value, d.config.TTL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -138,6 +142,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.ResourceID != resource.ResourceID {
|
||||
return errors.New("error deleting resource: resource IDs do not match")
|
||||
}
|
||||
|
|
191
vendor/github.com/xenolf/lego/providers/dns/linodev4/linodev4.go
generated
vendored
Normal file
191
vendor/github.com/xenolf/lego/providers/dns/linodev4/linodev4.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Package linodev4 implements a DNS provider for solving the DNS-01 challenge
|
||||
// using Linode DNS and Linode's APIv4
|
||||
package linodev4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/linode/linodego"
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
minTTL = 300
|
||||
dnsUpdateFreqMins = 15
|
||||
dnsUpdateFudgeSecs = 120
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
Token string
|
||||
PollingInterval time.Duration
|
||||
TTL int
|
||||
HTTPTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
PollingInterval: env.GetOrDefaultSecond("LINODE_POLLING_INTERVAL", 15*time.Second),
|
||||
TTL: env.GetOrDefaultInt("LINODE_TTL", minTTL),
|
||||
HTTPTimeout: env.GetOrDefaultSecond("LINODE_HTTP_TIMEOUT", 0),
|
||||
}
|
||||
}
|
||||
|
||||
type hostedZoneInfo struct {
|
||||
domainID int
|
||||
resourceName string
|
||||
}
|
||||
|
||||
// DNSProvider implements the acme.ChallengeProvider interface.
|
||||
type DNSProvider struct {
|
||||
config *Config
|
||||
client *linodego.Client
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Linode.
|
||||
// Credentials must be passed in the environment variable: LINODE_TOKEN.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get("LINODE_TOKEN")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("linodev4: %v", err)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.Token = values["LINODE_TOKEN"]
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
// NewDNSProviderConfig return a DNSProvider instance configured for Linode.
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("linodev4: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
if len(config.Token) == 0 {
|
||||
return nil, errors.New("linodev4: Linode Access Token missing")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("linodev4: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: config.Token})
|
||||
oauth2Client := &http.Client{
|
||||
Timeout: config.HTTPTimeout,
|
||||
Transport: &oauth2.Transport{
|
||||
Source: tokenSource,
|
||||
},
|
||||
}
|
||||
|
||||
client := linodego.NewClient(oauth2Client)
|
||||
client.SetUserAgent(fmt.Sprintf("lego-dns linodego/%s", linodego.Version))
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
client: &client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS
|
||||
// propagation. Adjusting here to cope with spikes in propagation times.
|
||||
func (d *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) +
|
||||
(minTTL * time.Second) +
|
||||
(dnsUpdateFudgeSecs * time.Second)
|
||||
interval = d.config.PollingInterval
|
||||
return
|
||||
}
|
||||
|
||||
// Present creates a TXT record using the specified parameters.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
zone, err := d.getHostedZoneInfo(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createOpts := linodego.DomainRecordCreateOptions{
|
||||
Name: acme.UnFqdn(fqdn),
|
||||
Target: value,
|
||||
TTLSec: d.config.TTL,
|
||||
Type: linodego.RecordTypeTXT,
|
||||
}
|
||||
|
||||
_, err = d.client.CreateDomainRecord(context.Background(), zone.domainID, createOpts)
|
||||
return err
|
||||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters.
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
zone, err := d.getHostedZoneInfo(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all TXT records for the specified domain.
|
||||
listOpts := linodego.NewListOptions(0, "{\"type\":\"TXT\"}")
|
||||
resources, err := d.client.ListDomainRecords(context.Background(), zone.domainID, listOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove the specified resource, if it exists.
|
||||
for _, resource := range resources {
|
||||
if (resource.Name == strings.TrimSuffix(fqdn, ".") || resource.Name == zone.resourceName) &&
|
||||
resource.Target == value {
|
||||
if err := d.client.DeleteDomainRecord(context.Background(), zone.domainID, resource.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *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
|
||||
}
|
||||
|
||||
// Query the authority zone.
|
||||
data, err := json.Marshal(map[string]string{"domain": acme.UnFqdn(authZone)})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listOpts := linodego.NewListOptions(0, string(data))
|
||||
domains, err := d.client.ListDomains(context.Background(), listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(domains) == 0 {
|
||||
return nil, fmt.Errorf("domain not found")
|
||||
}
|
||||
|
||||
return &hostedZoneInfo{
|
||||
domainID: domains[0].ID,
|
||||
resourceName: strings.TrimSuffix(fqdn, "."+authZone),
|
||||
}, nil
|
||||
}
|
189
vendor/github.com/xenolf/lego/providers/dns/namecheap/client.go
generated
vendored
189
vendor/github.com/xenolf/lego/providers/dns/namecheap/client.go
generated
vendored
|
@ -1,11 +1,18 @@
|
|||
package namecheap
|
||||
|
||||
import "encoding/xml"
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// host describes a DNS record returned by the Namecheap DNS gethosts API.
|
||||
// Record 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 Record struct {
|
||||
Type string `xml:",attr"`
|
||||
Name string `xml:",attr"`
|
||||
Address string `xml:",attr"`
|
||||
|
@ -32,7 +39,7 @@ type getHostsResponse struct {
|
|||
XMLName xml.Name `xml:"ApiResponse"`
|
||||
Status string `xml:"Status,attr"`
|
||||
Errors []apierror `xml:"Errors>Error"`
|
||||
Hosts []host `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
|
||||
Hosts []Record `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
|
||||
}
|
||||
|
||||
type getTldsResponse struct {
|
||||
|
@ -42,3 +49,177 @@ type getTldsResponse struct {
|
|||
Name string `xml:",attr"`
|
||||
} `xml:"CommandResponse>Tlds>Tld"`
|
||||
}
|
||||
|
||||
// getTLDs requests the list of available TLDs.
|
||||
// https://www.namecheap.com/support/api/methods/domains/get-tld-list.aspx
|
||||
func (d *DNSProvider) getTLDs() (map[string]string, error) {
|
||||
request, err := d.newRequestGet("namecheap.domains.getTldList")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gtr getTldsResponse
|
||||
err = d.do(request, >r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(gtr.Errors) > 0 {
|
||||
return nil, fmt.Errorf("%s [%d]", gtr.Errors[0].Description, gtr.Errors[0].Number)
|
||||
}
|
||||
|
||||
tlds := make(map[string]string)
|
||||
for _, t := range gtr.Result {
|
||||
tlds[t.Name] = t.Name
|
||||
}
|
||||
return tlds, nil
|
||||
}
|
||||
|
||||
// getHosts reads the full list of DNS host records.
|
||||
// https://www.namecheap.com/support/api/methods/domains-dns/get-hosts.aspx
|
||||
func (d *DNSProvider) getHosts(sld, tld string) ([]Record, error) {
|
||||
request, err := d.newRequestGet("namecheap.domains.dns.getHosts",
|
||||
addParam("SLD", sld),
|
||||
addParam("TLD", tld),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ghr getHostsResponse
|
||||
err = d.do(request, &ghr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ghr.Errors) > 0 {
|
||||
return nil, fmt.Errorf("%s [%d]", ghr.Errors[0].Description, ghr.Errors[0].Number)
|
||||
}
|
||||
|
||||
return ghr.Hosts, nil
|
||||
}
|
||||
|
||||
// setHosts writes the full list of DNS host records .
|
||||
// https://www.namecheap.com/support/api/methods/domains-dns/set-hosts.aspx
|
||||
func (d *DNSProvider) setHosts(sld, tld string, hosts []Record) error {
|
||||
req, err := d.newRequestPost("namecheap.domains.dns.setHosts",
|
||||
addParam("SLD", sld),
|
||||
addParam("TLD", tld),
|
||||
func(values url.Values) {
|
||||
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)
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var shr setHostsResponse
|
||||
err = d.do(req, &shr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(shr.Errors) > 0 {
|
||||
return fmt.Errorf("%s [%d]", shr.Errors[0].Description, shr.Errors[0].Number)
|
||||
}
|
||||
if shr.Result.IsSuccess != "true" {
|
||||
return fmt.Errorf("setHosts failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) do(req *http.Request, out interface{}) error {
|
||||
resp, err := d.config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
var body []byte
|
||||
body, err = readBody(resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTP error %d [%s]: %v", resp.StatusCode, http.StatusText(resp.StatusCode), err)
|
||||
}
|
||||
return fmt.Errorf("HTTP error %d [%s]: %s", resp.StatusCode, http.StatusText(resp.StatusCode), string(body))
|
||||
}
|
||||
|
||||
body, err := readBody(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := xml.Unmarshal(body, out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) newRequestGet(cmd string, params ...func(url.Values)) (*http.Request, error) {
|
||||
query := d.makeQuery(cmd, params...)
|
||||
|
||||
reqURL, err := url.Parse(d.config.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqURL.RawQuery = query.Encode()
|
||||
|
||||
return http.NewRequest(http.MethodGet, reqURL.String(), nil)
|
||||
}
|
||||
|
||||
func (d *DNSProvider) newRequestPost(cmd string, params ...func(url.Values)) (*http.Request, error) {
|
||||
query := d.makeQuery(cmd, params...)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, d.config.BaseURL, strings.NewReader(query.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) makeQuery(cmd string, params ...func(url.Values)) url.Values {
|
||||
queryParams := make(url.Values)
|
||||
queryParams.Set("ApiUser", d.config.APIUser)
|
||||
queryParams.Set("ApiKey", d.config.APIKey)
|
||||
queryParams.Set("UserName", d.config.APIUser)
|
||||
queryParams.Set("Command", cmd)
|
||||
queryParams.Set("ClientIp", d.config.ClientIP)
|
||||
|
||||
for _, param := range params {
|
||||
param(queryParams)
|
||||
}
|
||||
|
||||
return queryParams
|
||||
}
|
||||
|
||||
func addParam(key, value string) func(url.Values) {
|
||||
return func(values url.Values) {
|
||||
values.Set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func readBody(resp *http.Response) ([]byte, error) {
|
||||
if resp.Body == nil {
|
||||
return nil, fmt.Errorf("response body is nil")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
rawBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rawBody, nil
|
||||
}
|
||||
|
|
217
vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go
generated
vendored
217
vendor/github.com/xenolf/lego/providers/dns/namecheap/namecheap.go
generated
vendored
|
@ -3,12 +3,10 @@
|
|||
package namecheap
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -147,22 +145,28 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
||||
hosts, err := d.getHosts(ch)
|
||||
records, err := d.getHosts(ch.sld, ch.tld)
|
||||
if err != nil {
|
||||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
||||
d.addChallengeRecord(ch, &hosts)
|
||||
record := Record{
|
||||
Name: ch.key,
|
||||
Type: "TXT",
|
||||
Address: ch.keyValue,
|
||||
MXPref: "10",
|
||||
TTL: strconv.Itoa(d.config.TTL),
|
||||
}
|
||||
|
||||
records = append(records, record)
|
||||
|
||||
if d.config.Debug {
|
||||
for _, h := range hosts {
|
||||
log.Printf(
|
||||
"%-5.5s %-30.30s %-6s %-70.70s\n",
|
||||
h.Type, h.Name, h.TTL, h.Address)
|
||||
for _, h := range records {
|
||||
log.Printf("%-5.5s %-30.30s %-6s %-70.70s", h.Type, h.Name, h.TTL, h.Address)
|
||||
}
|
||||
}
|
||||
|
||||
err = d.setHosts(ch, hosts)
|
||||
err = d.setHosts(ch.sld, ch.tld, records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
@ -181,16 +185,25 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
||||
hosts, err := d.getHosts(ch)
|
||||
records, err := d.getHosts(ch.sld, ch.tld)
|
||||
if err != nil {
|
||||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
||||
if removed := d.removeChallengeRecord(ch, &hosts); !removed {
|
||||
// Find the challenge TXT record and remove it if found.
|
||||
var found bool
|
||||
for i, h := range records {
|
||||
if h.Name == ch.key && h.Type == "TXT" {
|
||||
records = append(records[:i], records[i+1:]...)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = d.setHosts(ch, hosts)
|
||||
err = d.setHosts(ch.sld, ch.tld, records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("namecheap: %v", err)
|
||||
}
|
||||
|
@ -243,189 +256,15 @@ func newChallenge(domain, keyAuth string, tlds map[string]string) (*challenge, e
|
|||
host = strings.Join(parts[:longest-1], ".")
|
||||
}
|
||||
|
||||
key, keyValue, _ := acme.DNS01Record(domain, keyAuth)
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
return &challenge{
|
||||
domain: domain,
|
||||
key: "_acme-challenge." + host,
|
||||
keyFqdn: key,
|
||||
keyValue: keyValue,
|
||||
keyFqdn: fqdn,
|
||||
keyValue: value,
|
||||
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.config.APIUser)
|
||||
v.Set("ApiKey", d.config.APIKey)
|
||||
v.Set("UserName", d.config.APIUser)
|
||||
v.Set("Command", cmd)
|
||||
v.Set("ClientIp", d.config.ClientIP)
|
||||
}
|
||||
|
||||
// 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, err := url.Parse(d.config.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqURL.RawQuery = values.Encode()
|
||||
|
||||
resp, err := d.config.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
|
||||
}
|
||||
|
||||
var gtr getTldsResponse
|
||||
if err := xml.Unmarshal(body, >r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(gtr.Errors) > 0 {
|
||||
return nil, fmt.Errorf("%s [%d]", gtr.Errors[0].Description, gtr.Errors[0].Number)
|
||||
}
|
||||
|
||||
tlds = make(map[string]string)
|
||||
for _, t := range gtr.Result {
|
||||
tlds[t.Name] = t.Name
|
||||
}
|
||||
return tlds, nil
|
||||
}
|
||||
|
||||
// getHosts reads the full list of DNS host records 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, err := url.Parse(d.config.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqURL.RawQuery = values.Encode()
|
||||
|
||||
resp, err := d.config.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
|
||||
}
|
||||
|
||||
var ghr getHostsResponse
|
||||
if err = xml.Unmarshal(body, &ghr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ghr.Errors) > 0 {
|
||||
return nil, fmt.Errorf("%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 := d.config.HTTPClient.PostForm(d.config.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
|
||||
}
|
||||
|
||||
var shr setHostsResponse
|
||||
if err := xml.Unmarshal(body, &shr); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(shr.Errors) > 0 {
|
||||
return fmt.Errorf("%s [%d]", shr.Errors[0].Description, shr.Errors[0].Number)
|
||||
}
|
||||
if shr.Result.IsSuccess != "true" {
|
||||
return fmt.Errorf("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: strconv.Itoa(d.config.TTL),
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
14
vendor/github.com/xenolf/lego/providers/dns/namedotcom/namedotcom.go
generated
vendored
14
vendor/github.com/xenolf/lego/providers/dns/namedotcom/namedotcom.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -15,6 +14,9 @@ import (
|
|||
"github.com/xenolf/lego/platform/config/env"
|
||||
)
|
||||
|
||||
// according to https://www.name.com/api-docs/DNS#CreateRecord
|
||||
const minTTL = 300
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
Username string
|
||||
|
@ -29,7 +31,7 @@ type Config struct {
|
|||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: env.GetOrDefaultInt("NAMECOM_TTL", 120),
|
||||
TTL: env.GetOrDefaultInt("NAMECOM_TTL", minTTL),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("NAMECOM_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond("NAMECOM_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||
HTTPClient: &http.Client{
|
||||
|
@ -56,7 +58,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
config := NewDefaultConfig()
|
||||
config.Username = values["NAMECOM_USERNAME"]
|
||||
config.APIToken = values["NAMECOM_API_TOKEN"]
|
||||
config.Server = os.Getenv("NAMECOM_SERVER")
|
||||
config.Server = env.GetOrFile("NAMECOM_SERVER")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
@ -87,6 +89,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("namedotcom: API token is required")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("namedotcom: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
client := namecom.New(config.Username, config.APIToken)
|
||||
client.Client = config.HTTPClient
|
||||
|
||||
|
@ -97,7 +103,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
3
vendor/github.com/xenolf/lego/providers/dns/nifcloud/nifcloud.go
generated
vendored
3
vendor/github.com/xenolf/lego/providers/dns/nifcloud/nifcloud.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/xenolf/lego/acme"
|
||||
|
@ -52,7 +51,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.BaseURL = os.Getenv("NIFCLOUD_DNS_ENDPOINT")
|
||||
config.BaseURL = env.GetOrFile("NIFCLOUD_DNS_ENDPOINT")
|
||||
config.AccessKey = values["NIFCLOUD_ACCESS_KEY_ID"]
|
||||
config.SecretKey = values["NIFCLOUD_SECRET_ACCESS_KEY"]
|
||||
|
||||
|
|
56
vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go
generated
vendored
56
vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go
generated
vendored
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/log"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
"gopkg.in/ns1/ns1-go.v2/rest"
|
||||
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
|
||||
|
@ -81,7 +82,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
@ -90,10 +91,36 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("ns1: %v", err)
|
||||
}
|
||||
|
||||
record := d.newTxtRecord(zone, fqdn, value, d.config.TTL)
|
||||
_, err = d.client.Records.Create(record)
|
||||
if err != nil && err != rest.ErrRecordExists {
|
||||
return fmt.Errorf("ns1: failed to create record [zone: %q, fqdn: %q]: %v", zone.Zone, fqdn, err)
|
||||
record, _, err := d.client.Records.Get(zone.Zone, acme.UnFqdn(fqdn), "TXT")
|
||||
|
||||
// Create a new record
|
||||
if err == rest.ErrRecordMissing || record == nil {
|
||||
log.Infof("Create a new record for [zone: %s, fqdn: %s, domain: %s]", zone.Zone, fqdn)
|
||||
|
||||
record = dns.NewRecord(zone.Zone, acme.UnFqdn(fqdn), "TXT")
|
||||
record.TTL = d.config.TTL
|
||||
record.Answers = []*dns.Answer{{Rdata: []string{value}}}
|
||||
|
||||
_, err = d.client.Records.Create(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ns1: failed to create record [zone: %q, fqdn: %q]: %v", zone.Zone, fqdn, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("ns1: failed to get the existing record: %v", err)
|
||||
}
|
||||
|
||||
// Update the existing records
|
||||
record.Answers = append(record.Answers, &dns.Answer{Rdata: []string{value}})
|
||||
|
||||
log.Infof("Update an existing record for [zone: %s, fqdn: %s, domain: %s]", zone.Zone, fqdn, domain)
|
||||
|
||||
_, err = d.client.Records.Update(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ns1: failed to update record [zone: %q, fqdn: %q]: %v", zone.Zone, fqdn, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -110,7 +137,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
name := acme.UnFqdn(fqdn)
|
||||
_, err = d.client.Records.Delete(zone.Zone, name, "TXT")
|
||||
return fmt.Errorf("ns1: failed to delete record [zone: %q, domain: %q]: %v", zone.Zone, name, err)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ns1: failed to delete record [zone: %q, domain: %q]: %v", zone.Zone, name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
|
@ -141,17 +171,3 @@ func getAuthZone(fqdn string) (string, error) {
|
|||
|
||||
return strings.TrimSuffix(authZone, "."), nil
|
||||
}
|
||||
|
||||
func (d *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}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
8
vendor/github.com/xenolf/lego/providers/dns/otc/otc.go
generated
vendored
8
vendor/github.com/xenolf/lego/providers/dns/otc/otc.go
generated
vendored
|
@ -113,6 +113,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("otc: credentials missing")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("otc: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
if config.IdentityEndpoint == "" {
|
||||
config.IdentityEndpoint = defaultIdentityEndpoint
|
||||
}
|
||||
|
@ -124,10 +128,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
if d.config.TTL < minTTL {
|
||||
d.config.TTL = minTTL
|
||||
}
|
||||
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("otc: %v", err)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/ovh/ovh.go
generated
vendored
|
@ -114,7 +114,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/pdns/pdns.go
generated
vendored
|
@ -110,7 +110,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
zone, err := d.getHostedZone(fqdn)
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go
generated
vendored
|
@ -146,7 +146,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
zoneID, err := d.getHostedZoneID(fqdn)
|
||||
|
|
5
vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go
generated
vendored
5
vendor/github.com/xenolf/lego/providers/dns/rfc2136/rfc2136.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -62,8 +61,8 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
|
||||
config := NewDefaultConfig()
|
||||
config.Nameserver = values["RFC2136_NAMESERVER"]
|
||||
config.TSIGKey = os.Getenv("RFC2136_TSIG_KEY")
|
||||
config.TSIGSecret = os.Getenv("RFC2136_TSIG_SECRET")
|
||||
config.TSIGKey = env.GetOrFile("RFC2136_TSIG_KEY")
|
||||
config.TSIGSecret = env.GetOrFile("RFC2136_TSIG_SECRET")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
|
187
vendor/github.com/xenolf/lego/providers/dns/route53/route53.go
generated
vendored
187
vendor/github.com/xenolf/lego/providers/dns/route53/route53.go
generated
vendored
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -35,7 +34,7 @@ func NewDefaultConfig() *Config {
|
|||
TTL: env.GetOrDefaultInt("AWS_TTL", 10),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("AWS_PROPAGATION_TIMEOUT", 2*time.Minute),
|
||||
PollingInterval: env.GetOrDefaultSecond("AWS_POLLING_INTERVAL", 4*time.Second),
|
||||
HostedZoneID: os.Getenv("AWS_HOSTED_ZONE_ID"),
|
||||
HostedZoneID: env.GetOrFile("AWS_HOSTED_ZONE_ID"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,17 +44,16 @@ type DNSProvider struct {
|
|||
config *Config
|
||||
}
|
||||
|
||||
// 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).
|
||||
// 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.
|
||||
// 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
|
||||
|
@ -67,57 +65,81 @@ func (d customRetryer) RetryRules(r *request.Request) time.Duration {
|
|||
return time.Duration(delay) * time.Millisecond
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance configured for the AWS
|
||||
// Route 53 service.
|
||||
// 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:
|
||||
// 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.
|
||||
// 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) {
|
||||
return NewDNSProviderConfig(NewDefaultConfig())
|
||||
}
|
||||
|
||||
// NewDNSProviderConfig takes a given config ans returns a custom configured
|
||||
// DNSProvider instance
|
||||
// NewDNSProviderConfig takes a given config ans returns a custom configured DNSProvider instance
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("route53: the configuration of the Route53 DNS provider is nil")
|
||||
}
|
||||
|
||||
r := customRetryer{}
|
||||
r.NumMaxRetries = config.MaxRetries
|
||||
sessionCfg := request.WithRetryer(aws.NewConfig(), r)
|
||||
retry := customRetryer{}
|
||||
retry.NumMaxRetries = config.MaxRetries
|
||||
sessionCfg := request.WithRetryer(aws.NewConfig(), retry)
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{Config: *sessionCfg})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cl := route53.New(sess)
|
||||
|
||||
return &DNSProvider{
|
||||
client: cl,
|
||||
config: config,
|
||||
}, nil
|
||||
cl := route53.New(sess)
|
||||
return &DNSProvider{client: cl, config: config}, nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS
|
||||
// propagation.
|
||||
func (r *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return r.config.PropagationTimeout, r.config.PollingInterval
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record using the specified parameters
|
||||
func (r *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
err := r.changeRecord("UPSERT", fqdn, `"`+value+`"`, r.config.TTL)
|
||||
hostedZoneID, err := d.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: failed to determine hosted zone ID: %v", err)
|
||||
}
|
||||
|
||||
records, err := d.getExistingRecordSets(hostedZoneID, fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %v", err)
|
||||
}
|
||||
|
||||
realValue := `"` + value + `"`
|
||||
|
||||
var found bool
|
||||
for _, record := range records {
|
||||
if aws.StringValue(record.Value) == realValue {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
records = append(records, &route53.ResourceRecord{Value: aws.String(realValue)})
|
||||
}
|
||||
|
||||
recordSet := &route53.ResourceRecordSet{
|
||||
Name: aws.String(fqdn),
|
||||
Type: aws.String("TXT"),
|
||||
TTL: aws.Int64(int64(d.config.TTL)),
|
||||
ResourceRecords: records,
|
||||
}
|
||||
|
||||
err = d.changeRecord(route53.ChangeActionUpsert, hostedZoneID, recordSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %v", err)
|
||||
}
|
||||
|
@ -125,61 +147,101 @@ func (r *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters
|
||||
func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
err := r.changeRecord("DELETE", fqdn, `"`+value+`"`, r.config.TTL)
|
||||
hostedZoneID, err := d.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine Route 53 hosted zone ID: %v", err)
|
||||
}
|
||||
|
||||
records, err := d.getExistingRecordSets(hostedZoneID, fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %v", err)
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
recordSet := &route53.ResourceRecordSet{
|
||||
Name: aws.String(fqdn),
|
||||
Type: aws.String("TXT"),
|
||||
TTL: aws.Int64(int64(d.config.TTL)),
|
||||
ResourceRecords: records,
|
||||
}
|
||||
|
||||
err = d.changeRecord(route53.ChangeActionDelete, hostedZoneID, recordSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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{
|
||||
func (d *DNSProvider) changeRecord(action, hostedZoneID string, recordSet *route53.ResourceRecordSet) error {
|
||||
recordSetInput := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneID),
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Comment: aws.String("Managed by Lego"),
|
||||
Changes: []*route53.Change{
|
||||
{
|
||||
Action: aws.String(action),
|
||||
ResourceRecordSet: recordSet,
|
||||
},
|
||||
},
|
||||
Changes: []*route53.Change{{
|
||||
Action: aws.String(action),
|
||||
ResourceRecordSet: recordSet,
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := r.client.ChangeResourceRecordSets(reqParams)
|
||||
resp, err := d.client.ChangeResourceRecordSets(recordSetInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change record set: %v", err)
|
||||
}
|
||||
|
||||
statusID := resp.ChangeInfo.Id
|
||||
changeID := resp.ChangeInfo.Id
|
||||
|
||||
return acme.WaitFor(r.config.PropagationTimeout, r.config.PollingInterval, func() (bool, error) {
|
||||
reqParams := &route53.GetChangeInput{
|
||||
Id: statusID,
|
||||
}
|
||||
resp, err := r.client.GetChange(reqParams)
|
||||
return acme.WaitFor(d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
|
||||
reqParams := &route53.GetChangeInput{Id: changeID}
|
||||
|
||||
resp, err := d.client.GetChange(reqParams)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to query change status: %v", err)
|
||||
}
|
||||
|
||||
if aws.StringValue(resp.ChangeInfo.Status) == route53.ChangeStatusInsync {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
return false, fmt.Errorf("unable to retrieve change: ID=%s", aws.StringValue(changeID))
|
||||
})
|
||||
}
|
||||
|
||||
func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
||||
if r.config.HostedZoneID != "" {
|
||||
return r.config.HostedZoneID, nil
|
||||
func (d *DNSProvider) getExistingRecordSets(hostedZoneID string, fqdn string) ([]*route53.ResourceRecord, error) {
|
||||
listInput := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneID),
|
||||
StartRecordName: aws.String(fqdn),
|
||||
StartRecordType: aws.String("TXT"),
|
||||
}
|
||||
|
||||
recordSetsOutput, err := d.client.ListResourceRecordSets(listInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if recordSetsOutput == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var records []*route53.ResourceRecord
|
||||
|
||||
for _, recordSet := range recordSetsOutput.ResourceRecordSets {
|
||||
if aws.StringValue(recordSet.Name) == fqdn {
|
||||
records = append(records, recordSet.ResourceRecords...)
|
||||
}
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
||||
if d.config.HostedZoneID != "" {
|
||||
return d.config.HostedZoneID, nil
|
||||
}
|
||||
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
|
@ -191,7 +253,7 @@ func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
|||
reqParams := &route53.ListHostedZonesByNameInput{
|
||||
DNSName: aws.String(acme.UnFqdn(authZone)),
|
||||
}
|
||||
resp, err := r.client.ListHostedZonesByName(reqParams)
|
||||
resp, err := d.client.ListHostedZonesByName(reqParams)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -215,14 +277,3 @@ func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
|||
|
||||
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)},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/sakuracloud/sakuracloud.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/sakuracloud/sakuracloud.go
generated
vendored
|
@ -85,7 +85,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
7
vendor/github.com/xenolf/lego/providers/dns/vegadns/vegadns.go
generated
vendored
7
vendor/github.com/xenolf/lego/providers/dns/vegadns/vegadns.go
generated
vendored
|
@ -5,7 +5,6 @@ package vegadns
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -50,8 +49,8 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
|
||||
config := NewDefaultConfig()
|
||||
config.BaseURL = values["VEGADNS_URL"]
|
||||
config.APIKey = os.Getenv("SECRET_VEGADNS_KEY")
|
||||
config.APISecret = os.Getenv("SECRET_VEGADNS_SECRET")
|
||||
config.APIKey = env.GetOrFile("SECRET_VEGADNS_KEY")
|
||||
config.APISecret = env.GetOrFile("SECRET_VEGADNS_SECRET")
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
@ -87,7 +86,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
2
vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/vultr/vultr.go
generated
vendored
|
@ -90,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the DNS-01 challenge.
|
||||
// Present creates a TXT record to fulfill the DNS-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue