mirror of
https://github.com/go-acme/lego.git
synced 2026-01-25 05:06:16 +00:00
chore: update linter (#2699)
This commit is contained in:
committed by
GitHub
parent
5dba10703f
commit
81e0f2b42a
2
.github/workflows/pr.yml
vendored
2
.github/workflows/pr.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: stable
|
||||
GOLANGCI_LINT_VERSION: v2.5.0
|
||||
GOLANGCI_LINT_VERSION: v2.6.0
|
||||
HUGO_VERSION: 0.148.2
|
||||
CGO_ENABLED: 0
|
||||
LEGO_E2E_TESTS: CI
|
||||
|
||||
@@ -50,11 +50,8 @@ linters:
|
||||
- tagliatelle
|
||||
- testpackage # not relevant
|
||||
- tparallel # not relevant
|
||||
- usestdlibvars # false-positive https://github.com/sashamelentyev/usestdlibvars/issues/96
|
||||
- varnamelen # not relevant
|
||||
- wrapcheck
|
||||
- wsl_v5 # should be enabled the future.
|
||||
- embeddedstructfieldcheck # should be enabled the future.
|
||||
|
||||
settings:
|
||||
depguard:
|
||||
|
||||
@@ -13,6 +13,7 @@ type AccountService service
|
||||
// New Creates a new account.
|
||||
func (a *AccountService) New(req acme.Account) (acme.ExtendedAccount, error) {
|
||||
var account acme.Account
|
||||
|
||||
resp, err := a.core.post(a.core.GetDirectory().NewAccountURL, req, &account)
|
||||
location := getLocation(resp)
|
||||
|
||||
@@ -51,10 +52,12 @@ func (a *AccountService) Get(accountURL string) (acme.Account, error) {
|
||||
}
|
||||
|
||||
var account acme.Account
|
||||
|
||||
_, err := a.core.postAsGet(accountURL, &account)
|
||||
if err != nil {
|
||||
return acme.Account{}, err
|
||||
}
|
||||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
@@ -65,6 +68,7 @@ func (a *AccountService) Update(accountURL string, req acme.Account) (acme.Accou
|
||||
}
|
||||
|
||||
var account acme.Account
|
||||
|
||||
_, err := a.core.post(accountURL, req, &account)
|
||||
if err != nil {
|
||||
return acme.Account{}, err
|
||||
@@ -81,6 +85,7 @@ func (a *AccountService) Deactivate(accountURL string) error {
|
||||
|
||||
req := acme.Account{Status: acme.StatusDeactivated}
|
||||
_, err := a.core.post(accountURL, req, nil)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ func getDirectory(do *sender.Doer, caDirURL string) (acme.Directory, error) {
|
||||
if dir.NewAccountURL == "" {
|
||||
return dir, errors.New("directory missing new registration URL")
|
||||
}
|
||||
|
||||
if dir.NewOrderURL == "" {
|
||||
return dir, errors.New("directory missing new order URL")
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ func (c *AuthorizationService) Get(authzURL string) (acme.Authorization, error)
|
||||
}
|
||||
|
||||
var authz acme.Authorization
|
||||
|
||||
_, err := c.core.postAsGet(authzURL, &authz)
|
||||
if err != nil {
|
||||
return acme.Authorization{}, err
|
||||
}
|
||||
|
||||
return authz, nil
|
||||
}
|
||||
|
||||
@@ -29,6 +31,8 @@ func (c *AuthorizationService) Deactivate(authzURL string) error {
|
||||
}
|
||||
|
||||
var disabledAuth acme.Authorization
|
||||
|
||||
_, err := c.core.post(authzURL, acme.Authorization{Status: acme.StatusDeactivated}, &disabledAuth)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||
// Challenge initiation is done by sending a JWS payload containing the trivial JSON object `{}`.
|
||||
// We use an empty struct instance as the postJSON payload here to achieve this result.
|
||||
var chlng acme.ExtendedChallenge
|
||||
|
||||
resp, err := c.core.post(chlgURL, struct{}{}, &chlng)
|
||||
if err != nil {
|
||||
return acme.ExtendedChallenge{}, err
|
||||
@@ -24,6 +25,7 @@ func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||
|
||||
chlng.AuthorizationURL = getLink(resp.Header, "up")
|
||||
chlng.RetryAfter = getRetryAfter(resp)
|
||||
|
||||
return chlng, nil
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||
}
|
||||
|
||||
var chlng acme.ExtendedChallenge
|
||||
|
||||
resp, err := c.core.postAsGet(chlgURL, &chlng)
|
||||
if err != nil {
|
||||
return acme.ExtendedChallenge{}, err
|
||||
@@ -41,5 +44,6 @@ func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||
|
||||
chlng.AuthorizationURL = getLink(resp.Header, "up")
|
||||
chlng.RetryAfter = getRetryAfter(resp)
|
||||
|
||||
return chlng, nil
|
||||
}
|
||||
|
||||
@@ -11,10 +11,11 @@ import (
|
||||
|
||||
// Manager Manages nonces.
|
||||
type Manager struct {
|
||||
sync.Mutex
|
||||
|
||||
do *sender.Doer
|
||||
nonceURL string
|
||||
nonces []string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// NewManager Creates a new Manager.
|
||||
@@ -36,6 +37,7 @@ func (n *Manager) Pop() (string, bool) {
|
||||
|
||||
nonce := n.nonces[len(n.nonces)-1]
|
||||
n.nonces = n.nonces[:len(n.nonces)-1]
|
||||
|
||||
return nonce, true
|
||||
}
|
||||
|
||||
@@ -43,6 +45,7 @@ func (n *Manager) Pop() (string, bool) {
|
||||
func (n *Manager) Push(nonce string) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
n.nonces = append(n.nonces, nonce)
|
||||
}
|
||||
|
||||
@@ -51,6 +54,7 @@ func (n *Manager) Nonce() (string, error) {
|
||||
if nonce, ok := n.Pop(); ok {
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
return n.getNonce()
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,13 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
|
||||
|
||||
ch := make(chan bool)
|
||||
resultCh := make(chan bool)
|
||||
|
||||
go func() {
|
||||
_, errN := manager.Nonce()
|
||||
if errN != nil {
|
||||
t.Log(errN)
|
||||
}
|
||||
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
@@ -42,13 +44,16 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
|
||||
if errN != nil {
|
||||
t.Log(errN)
|
||||
}
|
||||
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
<-ch
|
||||
<-ch
|
||||
|
||||
resultCh <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-resultCh:
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
|
||||
@@ -36,6 +36,7 @@ func (j *JWS) SetKid(kid string) {
|
||||
// SignContent Signs a content with the JWS.
|
||||
func (j *JWS) SignContent(url string, content []byte) (*jose.JSONWebSignature, error) {
|
||||
var alg jose.SignatureAlgorithm
|
||||
|
||||
switch k := j.privKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
alg = jose.RS256
|
||||
@@ -72,12 +73,14 @@ func (j *JWS) SignContent(url string, content []byte) (*jose.JSONWebSignature, e
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign content: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
// SignEABContent Signs an external account binding content with the JWS.
|
||||
func (j *JWS) SignEABContent(url, kid string, hmac []byte) (*jose.JSONWebSignature, error) {
|
||||
jwk := jose.JSONWebKey{Key: j.privKey}
|
||||
|
||||
jwkJSON, err := jwk.Public().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("acme: error encoding eab jwk key: %w", err)
|
||||
@@ -108,6 +111,7 @@ func (j *JWS) SignEABContent(url, kid string, hmac []byte) (*jose.JSONWebSignatu
|
||||
// GetKeyAuthorization Gets the key authorization for a token.
|
||||
func (j *JWS) GetKeyAuthorization(token string) (string, error) {
|
||||
var publicKey crypto.PublicKey
|
||||
|
||||
switch k := j.privKey.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
publicKey = k.Public()
|
||||
|
||||
@@ -31,11 +31,13 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
|
||||
|
||||
ch := make(chan bool)
|
||||
resultCh := make(chan bool)
|
||||
|
||||
go func() {
|
||||
_, errN := manager.Nonce()
|
||||
if errN != nil {
|
||||
t.Log(errN)
|
||||
}
|
||||
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
@@ -43,13 +45,16 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
|
||||
if errN != nil {
|
||||
t.Log(errN)
|
||||
}
|
||||
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
<-ch
|
||||
<-ch
|
||||
|
||||
resultCh <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-resultCh:
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
|
||||
@@ -127,6 +127,7 @@ func checkError(req *http.Request, resp *http.Response) error {
|
||||
}
|
||||
|
||||
var errorDetails *acme.ProblemDetails
|
||||
|
||||
err = json.Unmarshal(body, &errorDetails)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d ::%s :: %s :: %w :: %s", resp.StatusCode, req.Method, req.URL, err, string(body))
|
||||
@@ -150,6 +151,7 @@ func checkError(req *http.Request, resp *http.Response) error {
|
||||
|
||||
return errorDetails
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
func TestDo_UserAgentOnAllHTTPMethod(t *testing.T) {
|
||||
var ua, method string
|
||||
|
||||
server := httptest.NewTLSServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
|
||||
ua = r.Header.Get("User-Agent")
|
||||
method = r.Method
|
||||
@@ -60,9 +61,11 @@ func TestDo_CustomUserAgent(t *testing.T) {
|
||||
ua := doer.formatUserAgent()
|
||||
assert.Contains(t, ua, ourUserAgent)
|
||||
assert.Contains(t, ua, customUA)
|
||||
|
||||
if strings.HasSuffix(ua, " ") {
|
||||
t.Errorf("UA should not have trailing spaces; got '%s'", ua)
|
||||
}
|
||||
|
||||
assert.Len(t, strings.Split(ua, " "), 5)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acm
|
||||
}
|
||||
|
||||
var order acme.Order
|
||||
|
||||
resp, err := o.core.post(o.core.GetDirectory().NewOrderURL, orderReq, &order)
|
||||
if err != nil {
|
||||
are := &acme.AlreadyReplacedError{}
|
||||
@@ -107,6 +108,7 @@ func (o *OrderService) Get(orderURL string) (acme.ExtendedOrder, error) {
|
||||
}
|
||||
|
||||
var order acme.Order
|
||||
|
||||
_, err := o.core.postAsGet(orderURL, &order)
|
||||
if err != nil {
|
||||
return acme.ExtendedOrder{}, err
|
||||
@@ -122,6 +124,7 @@ func (o *OrderService) UpdateForCSR(orderURL string, csr []byte) (acme.ExtendedO
|
||||
}
|
||||
|
||||
var order acme.Order
|
||||
|
||||
_, err := o.core.post(orderURL, csrMsg, &order)
|
||||
if err != nil {
|
||||
return acme.ExtendedOrder{}, err
|
||||
|
||||
@@ -32,6 +32,7 @@ func TestOrderService_NewWithOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
order := acme.Order{}
|
||||
|
||||
err = json.Unmarshal(body, &order)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
@@ -107,6 +108,7 @@ func readSignedBody(r *http.Request, privateKey *rsa.PrivateKey) ([]byte, error)
|
||||
}
|
||||
|
||||
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
|
||||
|
||||
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -23,11 +23,13 @@ func getLinks(header http.Header, rel string) []string {
|
||||
linkExpr := regexp.MustCompile(`<(.+?)>(?:;[^;]+)*?;\s*rel="(.+?)"`)
|
||||
|
||||
var links []string
|
||||
|
||||
for _, link := range header["Link"] {
|
||||
for _, m := range linkExpr.FindAllStringSubmatch(link, -1) {
|
||||
if len(m) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
if m[2] == rel {
|
||||
links = append(links, m[1])
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ type Meta struct {
|
||||
// ExtendedAccount an extended Account.
|
||||
type ExtendedAccount struct {
|
||||
Account
|
||||
|
||||
// Contains the value of the response header `Location`
|
||||
Location string `json:"-"`
|
||||
}
|
||||
@@ -220,11 +221,11 @@ type Authorization struct {
|
||||
// The timestamp after which the server will consider this authorization invalid,
|
||||
// encoded in the format specified in RFC 3339 [RFC3339].
|
||||
// This field is REQUIRED for objects with "valid" in the "status" field.
|
||||
Expires time.Time `json:"expires,omitempty"`
|
||||
Expires time.Time `json:"expires,omitzero"`
|
||||
|
||||
// identifier (required, object):
|
||||
// The identifier that the account is authorized to represent
|
||||
Identifier Identifier `json:"identifier,omitempty"`
|
||||
Identifier Identifier `json:"identifier"`
|
||||
|
||||
// challenges (required, array of objects):
|
||||
// For pending authorizations, the challenges that the client can fulfill in order to prove possession of the identifier.
|
||||
@@ -244,6 +245,7 @@ type Authorization struct {
|
||||
// ExtendedChallenge a extended Challenge.
|
||||
type ExtendedChallenge struct {
|
||||
Challenge
|
||||
|
||||
// Contains the value of the response header `Retry-After`
|
||||
RetryAfter string `json:"-"`
|
||||
// Contains the value of the response header `Link` rel="up"
|
||||
@@ -270,7 +272,7 @@ type Challenge struct {
|
||||
// The time at which the server validated this challenge,
|
||||
// encoded in the format specified in RFC 3339 [RFC3339].
|
||||
// This field is REQUIRED if the "status" field is "valid".
|
||||
Validated time.Time `json:"validated,omitempty"`
|
||||
Validated time.Time `json:"validated,omitzero"`
|
||||
|
||||
// error (optional, object):
|
||||
// Error that occurred while the server was validating the challenge, if any,
|
||||
|
||||
@@ -2,6 +2,7 @@ package acme
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors types.
|
||||
@@ -27,21 +28,25 @@ type ProblemDetails struct {
|
||||
}
|
||||
|
||||
func (p *ProblemDetails) Error() string {
|
||||
msg := fmt.Sprintf("acme: error: %d", p.HTTPStatus)
|
||||
var msg strings.Builder
|
||||
|
||||
msg.WriteString(fmt.Sprintf("acme: error: %d", p.HTTPStatus))
|
||||
|
||||
if p.Method != "" || p.URL != "" {
|
||||
msg += fmt.Sprintf(" :: %s :: %s", p.Method, p.URL)
|
||||
msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Method, p.URL))
|
||||
}
|
||||
msg += fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail)
|
||||
|
||||
msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail))
|
||||
|
||||
for _, sub := range p.SubProblems {
|
||||
msg += fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail)
|
||||
msg.WriteString(fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail))
|
||||
}
|
||||
|
||||
if p.Instance != "" {
|
||||
msg += ", url: " + p.Instance
|
||||
msg.WriteString(", url: " + p.Instance)
|
||||
}
|
||||
|
||||
return msg
|
||||
return msg.String()
|
||||
}
|
||||
|
||||
// SubProblem a "subproblems".
|
||||
@@ -49,7 +54,7 @@ func (p *ProblemDetails) Error() string {
|
||||
type SubProblem struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
Identifier Identifier `json:"identifier,omitempty"`
|
||||
Identifier Identifier `json:"identifier"`
|
||||
}
|
||||
|
||||
// NonceError represents the error which is returned
|
||||
|
||||
@@ -57,8 +57,10 @@ type DERCertificateBytes []byte
|
||||
// ParsePEMBundle parses a certificate bundle from top to bottom and returns
|
||||
// a slice of x509 certificates. This function will error if no certificates are found.
|
||||
func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
|
||||
var certificates []*x509.Certificate
|
||||
var certDERBlock *pem.Block
|
||||
var (
|
||||
certificates []*x509.Certificate
|
||||
certDERBlock *pem.Block
|
||||
)
|
||||
|
||||
for {
|
||||
certDERBlock, bundle = pem.Decode(bundle)
|
||||
@@ -71,6 +73,7 @@ func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certificates = append(certificates, cert)
|
||||
}
|
||||
}
|
||||
@@ -152,8 +155,11 @@ type CSROptions struct {
|
||||
}
|
||||
|
||||
func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) {
|
||||
var dnsNames []string
|
||||
var ipAddresses []net.IP
|
||||
var (
|
||||
dnsNames []string
|
||||
ipAddresses []net.IP
|
||||
)
|
||||
|
||||
for _, altname := range opts.SAN {
|
||||
if ip := net.ParseIP(altname); ip != nil {
|
||||
ipAddresses = append(ipAddresses, ip)
|
||||
@@ -185,6 +191,7 @@ func PEMEncode(data any) []byte {
|
||||
|
||||
func PEMBlock(data any) *pem.Block {
|
||||
var pemBlock *pem.Block
|
||||
|
||||
switch key := data.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
keyBytes, _ := x509.MarshalECPrivateKey(key)
|
||||
@@ -265,6 +272,7 @@ func ExtractDomains(cert *x509.Certificate) []string {
|
||||
if sanDomain == cert.Subject.CommonName {
|
||||
continue
|
||||
}
|
||||
|
||||
domains = append(domains, sanDomain)
|
||||
}
|
||||
|
||||
@@ -316,6 +324,7 @@ func GeneratePemCert(privateKey *rsa.PrivateKey, domain string, extensions []pki
|
||||
|
||||
func generateDerCert(privateKey *rsa.PrivateKey, expiration time.Time, domain string, extensions []pkix.Extension) ([]byte, error) {
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -179,6 +179,7 @@ func TestParsePEMPrivateKey(t *testing.T) {
|
||||
// ignoring precomputed values.
|
||||
decoded, err := ParsePEMPrivateKey(pemPrivateKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
decodedRsaPrivateKey := decoded.(*rsa.PrivateKey)
|
||||
require.True(t, decodedRsaPrivateKey.Equal(privateKey))
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
||||
var responses []acme.Authorization
|
||||
|
||||
failures := newObtainError()
|
||||
|
||||
for range len(order.Authorizations) {
|
||||
select {
|
||||
case res := <-resc:
|
||||
@@ -62,6 +63,7 @@ func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force boo
|
||||
}
|
||||
|
||||
log.Infof("Deactivating auth: %s", authzURL)
|
||||
|
||||
if c.core.Authorizations.Deactivate(authzURL) != nil {
|
||||
log.Infof("Unable to deactivate the authorization: %s", authzURL)
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
||||
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
||||
|
||||
failures := newObtainError()
|
||||
|
||||
cert, err := c.getForOrder(domains, order, request)
|
||||
if err != nil {
|
||||
for _, auth := range authz {
|
||||
@@ -295,6 +296,7 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, requ
|
||||
|
||||
if privateKey == nil {
|
||||
var err error
|
||||
|
||||
privateKey, err = certcrypto.GeneratePrivateKey(c.options.KeyType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -490,6 +492,7 @@ type RenewOptions struct {
|
||||
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||
//
|
||||
// For private key reuse the PrivateKey property of the passed in Resource should be non-nil.
|
||||
//
|
||||
// Deprecated: use RenewWithOptions instead.
|
||||
func (c *Certifier) Renew(certRes Resource, bundle, mustStaple bool, preferredChain string) (*Resource, error) {
|
||||
return c.RenewWithOptions(certRes, &RenewOptions{
|
||||
@@ -722,6 +725,7 @@ func checkOrderStatus(order acme.ExtendedOrder) (bool, error) {
|
||||
// https://www.rfc-editor.org/rfc/rfc5280.html#section-7
|
||||
func sanitizeDomain(domains []string) []string {
|
||||
var sanitizedDomains []string
|
||||
|
||||
for _, domain := range domains {
|
||||
sanitizedDomain, err := idna.ToASCII(domain)
|
||||
if err != nil {
|
||||
@@ -730,5 +734,6 @@ func sanitizeDomain(domains []string) []string {
|
||||
sanitizedDomains = append(sanitizedDomains, sanitizedDomain)
|
||||
}
|
||||
}
|
||||
|
||||
return sanitizedDomains
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse
|
||||
defer resp.Body.Close()
|
||||
|
||||
var info RenewalInfoResponse
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -40,5 +40,6 @@ func GetTargetedDomain(authz acme.Authorization) string {
|
||||
if authz.Wildcard {
|
||||
return "*." + authz.Identifier.Value
|
||||
}
|
||||
|
||||
return authz.Identifier.Value
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ func CondOption(condition bool, opt ChallengeOption) ChallengeOption {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
@@ -118,6 +119,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
info := GetChallengeInfo(authz.Identifier.Value, keyAuth)
|
||||
|
||||
var timeout, interval time.Duration
|
||||
|
||||
switch provider := c.provider.(type) {
|
||||
case challenge.ProviderTimeout:
|
||||
timeout, interval = provider.Timeout()
|
||||
@@ -134,6 +136,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
if !stop || errP != nil {
|
||||
log.Infof("[%s] acme: Waiting for DNS record propagation.", domain)
|
||||
}
|
||||
|
||||
return stop, errP
|
||||
})
|
||||
if err != nil {
|
||||
@@ -141,6 +144,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
}
|
||||
|
||||
chlng.KeyAuthorization = keyAuth
|
||||
|
||||
return c.validate(c.core, domain, chlng)
|
||||
}
|
||||
|
||||
@@ -165,6 +169,7 @@ func (c *Challenge) Sequential() (bool, time.Duration) {
|
||||
if p, ok := c.provider.(sequential); ok {
|
||||
return ok, p.Sequential()
|
||||
}
|
||||
|
||||
return false, 0
|
||||
}
|
||||
|
||||
@@ -173,6 +178,7 @@ type sequential interface {
|
||||
}
|
||||
|
||||
// GetRecord returns a DNS record which will fulfill the `dns-01` challenge.
|
||||
//
|
||||
// Deprecated: use GetChallengeInfo instead.
|
||||
func GetRecord(domain, keyAuth string) (fqdn, value string) {
|
||||
info := GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
@@ -18,6 +18,7 @@ func TestDNSProviderManual(t *testing.T) {
|
||||
Build(t))
|
||||
|
||||
backupStdin := os.Stdin
|
||||
|
||||
defer func() { os.Stdin = backupStdin }()
|
||||
|
||||
testCases := []struct {
|
||||
|
||||
@@ -184,6 +184,7 @@ func TestChallenge_Solve(t *testing.T) {
|
||||
if test.preCheck != nil {
|
||||
options = append(options, WrapPreCheck(test.preCheck))
|
||||
}
|
||||
|
||||
chlg := NewChallenge(core, test.validate, test.provider, options...)
|
||||
|
||||
authz := acme.Authorization{
|
||||
|
||||
@@ -19,6 +19,7 @@ func UnFqdn(name string) string {
|
||||
if n != 0 && name[n-1] == '.' {
|
||||
return name[:n-1]
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ func mockResolver(t *testing.T, addr net.Addr) {
|
||||
require.NoError(t, err)
|
||||
|
||||
originalDefaultNameserverPort := defaultNameserverPort
|
||||
|
||||
t.Cleanup(func() {
|
||||
defaultNameserverPort = originalDefaultNameserverPort
|
||||
})
|
||||
@@ -47,6 +48,7 @@ func mockResolver(t *testing.T, addr net.Addr) {
|
||||
defaultNameserverPort = port
|
||||
|
||||
originalResolver := net.DefaultResolver
|
||||
|
||||
t.Cleanup(func() {
|
||||
net.DefaultResolver = originalResolver
|
||||
})
|
||||
@@ -70,6 +72,7 @@ func useAsNameserver(t *testing.T, addr net.Addr) {
|
||||
})
|
||||
|
||||
originalRecursiveNameservers := recursiveNameservers
|
||||
|
||||
t.Cleanup(func() {
|
||||
recursiveNameservers = originalRecursiveNameservers
|
||||
})
|
||||
|
||||
@@ -81,6 +81,7 @@ func getNameservers(path string, defaults []string) []string {
|
||||
|
||||
func ParseNameservers(servers []string) []string {
|
||||
var resolvers []string
|
||||
|
||||
for _, resolver := range servers {
|
||||
// ensure all servers have a port number
|
||||
if _, _, err := net.SplitHostPort(resolver); err != nil {
|
||||
@@ -89,6 +90,7 @@ func ParseNameservers(servers []string) []string {
|
||||
resolvers = append(resolvers, resolver)
|
||||
}
|
||||
}
|
||||
|
||||
return resolvers
|
||||
}
|
||||
|
||||
@@ -132,6 +134,7 @@ func FindPrimaryNsByFqdnCustom(fqdn string, nameservers []string) (string, error
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
||||
}
|
||||
|
||||
return soa.primaryNs, nil
|
||||
}
|
||||
|
||||
@@ -148,6 +151,7 @@ func FindZoneByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
||||
}
|
||||
|
||||
return soa.zone, nil
|
||||
}
|
||||
|
||||
@@ -172,8 +176,10 @@ func lookupSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error)
|
||||
}
|
||||
|
||||
func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
||||
var err error
|
||||
var r *dns.Msg
|
||||
var (
|
||||
err error
|
||||
r *dns.Msg
|
||||
)
|
||||
|
||||
for domain := range DomainsSeq(fqdn) {
|
||||
r, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
|
||||
@@ -229,9 +235,11 @@ func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (
|
||||
return nil, &DNSError{Message: "empty list of nameservers"}
|
||||
}
|
||||
|
||||
var r *dns.Msg
|
||||
var err error
|
||||
var errAll error
|
||||
var (
|
||||
r *dns.Msg
|
||||
err error
|
||||
errAll error
|
||||
)
|
||||
|
||||
for _, ns := range nameservers {
|
||||
r, err = sendDNSQuery(m, ns)
|
||||
@@ -264,6 +272,7 @@ func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
|
||||
func sendDNSQuery(m *dns.Msg, ns string) (*dns.Msg, error) {
|
||||
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_DNS_TCP_ONLY")); ok {
|
||||
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
|
||||
|
||||
r, _, err := tcp.Exchange(m, ns)
|
||||
if err != nil {
|
||||
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
|
||||
|
||||
@@ -29,6 +29,7 @@ func WrapPreCheck(wrap WrapPreCheckFunc) ChallengeOption {
|
||||
}
|
||||
|
||||
// DisableCompletePropagationRequirement obsolete.
|
||||
//
|
||||
// Deprecated: use DisableAuthoritativeNssPropagationRequirement instead.
|
||||
func DisableCompletePropagationRequirement() ChallengeOption {
|
||||
return DisableAuthoritativeNssPropagationRequirement()
|
||||
@@ -140,9 +141,11 @@ func checkNameserversPropagation(fqdn, value string, nameservers []string, addPo
|
||||
var records []string
|
||||
|
||||
var found bool
|
||||
|
||||
for _, rr := range r.Answer {
|
||||
if txt, ok := rr.(*dns.TXT); ok {
|
||||
record := strings.Join(txt.Txt, "")
|
||||
|
||||
records = append(records, record)
|
||||
if record == value {
|
||||
found = true
|
||||
|
||||
@@ -88,6 +88,7 @@ func (m *forwardedMatcher) matches(r *http.Request, domain string) bool {
|
||||
}
|
||||
|
||||
host := fwds[0]["host"]
|
||||
|
||||
return matchDomain(host, domain)
|
||||
}
|
||||
|
||||
@@ -99,6 +100,7 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
|
||||
inquote := false
|
||||
|
||||
pos := 0
|
||||
|
||||
l := len(s)
|
||||
for i := 0; i < l; i++ {
|
||||
r := rune(s[i])
|
||||
@@ -110,6 +112,7 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
|
||||
pos = i
|
||||
inquote = false
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -118,6 +121,7 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("unexpected quoted string as pos %d", i)
|
||||
}
|
||||
|
||||
inquote = true
|
||||
pos = i + 1
|
||||
|
||||
@@ -137,6 +141,7 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
|
||||
val = s[pos:i]
|
||||
cur[key] = val
|
||||
}
|
||||
|
||||
elements = append(elements, cur)
|
||||
cur = make(map[string]string)
|
||||
key = ""
|
||||
@@ -159,11 +164,14 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
|
||||
if pos < len(s) {
|
||||
val = s[pos:]
|
||||
}
|
||||
|
||||
cur[key] = val
|
||||
}
|
||||
|
||||
if len(cur) > 0 {
|
||||
elements = append(elements, cur)
|
||||
}
|
||||
|
||||
return elements, nil
|
||||
}
|
||||
|
||||
@@ -178,6 +186,7 @@ func skipWS(s string, i int) int {
|
||||
for isWS(rune(s[i+1])) {
|
||||
i++
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("[%s] acme: error presenting token: %w", domain, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := c.provider.CleanUp(authz.Identifier.Value, chlng.Token, keyAuth)
|
||||
if err != nil {
|
||||
@@ -86,5 +87,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
}
|
||||
|
||||
chlng.KeyAuthorization = keyAuth
|
||||
|
||||
return c.validate(c.core, domain, chlng)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ func NewUnixProviderServer(socketPath string, mode fs.FileMode) *ProviderServer
|
||||
// Present starts a web server and makes the token available at `ChallengePath(token)` for web requests.
|
||||
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
||||
var err error
|
||||
|
||||
s.listener, err = net.Listen(s.network, s.GetAddress())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not start HTTP server for challenge: %w", err)
|
||||
@@ -120,6 +121,7 @@ func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
||||
}
|
||||
|
||||
log.Infof("[%s] Served key authentication", domain)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ func TestChallenge(t *testing.T) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bodyStr := string(body)
|
||||
|
||||
if bodyStr != chlng.KeyAuthorization {
|
||||
@@ -157,6 +158,7 @@ func TestChallengeUnix(t *testing.T) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bodyStr := string(body)
|
||||
|
||||
if bodyStr != chlng.KeyAuthorization {
|
||||
@@ -224,6 +226,7 @@ func (h *testProxyHeader) update(r *http.Request) {
|
||||
if h == nil || len(h.values) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if h.name == "Host" {
|
||||
r.Host = h.values[0]
|
||||
} else if h.name != "" {
|
||||
@@ -385,6 +388,7 @@ func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectErro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.update(req)
|
||||
extra.update(req)
|
||||
|
||||
@@ -402,6 +406,7 @@ func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectErro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bodyStr := string(body)
|
||||
|
||||
if bodyStr != chlng.KeyAuthorization {
|
||||
|
||||
@@ -16,10 +16,12 @@ func (e obtainError) Error() string {
|
||||
for domain := range e {
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
|
||||
sort.Strings(domains)
|
||||
|
||||
for _, domain := range domains {
|
||||
_, _ = fmt.Fprintf(buffer, "[%s] %s\n", domain, e[domain])
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
@@ -50,11 +50,14 @@ func NewProber(solverManager *SolverManager) *Prober {
|
||||
func (p *Prober) Solve(authorizations []acme.Authorization) error {
|
||||
failures := make(obtainError)
|
||||
|
||||
var authSolvers []*selectedAuthSolver
|
||||
var authSolversSequential []*selectedAuthSolver
|
||||
var (
|
||||
authSolvers []*selectedAuthSolver
|
||||
authSolversSequential []*selectedAuthSolver
|
||||
)
|
||||
|
||||
// Loop through the resources, basically through the domains.
|
||||
// First pass just selects a solver for each authz.
|
||||
|
||||
for _, authz := range authorizations {
|
||||
domain := challenge.GetTargetedDomain(authz)
|
||||
if authz.Status == acme.StatusValid {
|
||||
@@ -90,6 +93,7 @@ func (p *Prober) Solve(authorizations []acme.Authorization) error {
|
||||
if len(failures) > 0 {
|
||||
return failures
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -102,7 +106,9 @@ func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
||||
err := solvr.PreSolve(authSolver.authz)
|
||||
if err != nil {
|
||||
failures[domain] = err
|
||||
|
||||
cleanUp(authSolver.solver, authSolver.authz)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -111,7 +117,9 @@ func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
||||
err := authSolver.solver.Solve(authSolver.authz)
|
||||
if err != nil {
|
||||
failures[domain] = err
|
||||
|
||||
cleanUp(authSolver.solver, authSolver.authz)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -149,6 +157,7 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
||||
// Finally solve all challenges for real
|
||||
for _, authSolver := range authSolvers {
|
||||
authz := authSolver.authz
|
||||
|
||||
domain := challenge.GetTargetedDomain(authz)
|
||||
if failures[domain] != nil {
|
||||
// already failed in previous loop
|
||||
@@ -165,6 +174,7 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
||||
func cleanUp(solvr solver, authz acme.Authorization) {
|
||||
if solvr, ok := solvr.(cleanup); ok {
|
||||
domain := challenge.GetTargetedDomain(authz)
|
||||
|
||||
err := solvr.CleanUp(authz)
|
||||
if err != nil {
|
||||
log.Warnf("[%s] acme: cleaning up failed: %v ", domain, err)
|
||||
|
||||
@@ -71,6 +71,7 @@ func (c *SolverManager) chooseSolver(authz acme.Authorization) solver {
|
||||
log.Infof("[%s] acme: use %s solver", domain, chlg.Type)
|
||||
return solvr
|
||||
}
|
||||
|
||||
log.Infof("[%s] acme: Could not find solver for: %s", domain, chlg.Type)
|
||||
}
|
||||
|
||||
@@ -101,6 +102,7 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
|
||||
// https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md#section-82
|
||||
ra = 5
|
||||
}
|
||||
|
||||
initialInterval := time.Duration(ra) * time.Second
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -162,6 +164,7 @@ func checkAuthorizationStatus(authz acme.Authorization) (bool, error) {
|
||||
return false, fmt.Errorf("invalid authorization: %w", chlg.Err())
|
||||
}
|
||||
}
|
||||
|
||||
return false, errors.New("invalid authorization")
|
||||
default:
|
||||
return false, fmt.Errorf("the server returned an unexpected authorization status: %s", authz.Status)
|
||||
|
||||
@@ -260,6 +260,7 @@ func validateNoBody(privateKey *rsa.PrivateKey, r *http.Request) error {
|
||||
}
|
||||
|
||||
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
|
||||
|
||||
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -276,5 +277,6 @@ func validateNoBody(privateKey *rsa.PrivateKey, r *http.Request) error {
|
||||
if bodyStr := string(body); bodyStr != "{}" && bodyStr != "" {
|
||||
return fmt.Errorf(`expected JWS POST body "{}" or "", got %q`, bodyStr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("[%s] acme: error presenting token: %w", challenge.GetTargetedDomain(authz), err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := c.provider.CleanUp(domain, chlng.Token, keyAuth)
|
||||
if err != nil {
|
||||
@@ -92,6 +93,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
||||
}
|
||||
|
||||
chlng.KeyAuthorization = keyAuth
|
||||
|
||||
return c.validate(c.core, domain, chlng)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ func TestChallenge(t *testing.T) {
|
||||
assert.NotEmpty(t, remoteCert.Extensions, "Expected the challenge certificate to contain extensions")
|
||||
|
||||
idx := -1
|
||||
|
||||
for i, ext := range remoteCert.Extensions {
|
||||
if idPeAcmeIdentifierV1.Equal(ext.Id) {
|
||||
idx = i
|
||||
@@ -145,18 +146,24 @@ func TestChallengeIPaddress(t *testing.T) {
|
||||
assert.True(t, net.ParseIP("127.0.0.1").Equal(remoteCert.IPAddresses[0]), "challenge certificate IPAddress ")
|
||||
assert.NotEmpty(t, remoteCert.Extensions, "Expected the challenge certificate to contain extensions")
|
||||
|
||||
var foundAcmeIdentifier bool
|
||||
var extValue []byte
|
||||
var (
|
||||
foundAcmeIdentifier bool
|
||||
extValue []byte
|
||||
)
|
||||
|
||||
for _, ext := range remoteCert.Extensions {
|
||||
if idPeAcmeIdentifierV1.Equal(ext.Id) {
|
||||
assert.True(t, ext.Critical, "Expected the challenge certificate id-pe-acmeIdentifier extension to be marked as critical")
|
||||
|
||||
foundAcmeIdentifier = true
|
||||
extValue = ext.Value
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
require.True(t, foundAcmeIdentifier, "Expected the challenge certificate to contain an extension with the id-pe-acmeIdentifier id,")
|
||||
|
||||
zBytes := sha256.Sum256([]byte(chlng.KeyAuthorization))
|
||||
value, err := asn1.Marshal(zBytes[:sha256.Size])
|
||||
require.NoError(t, err, "Expected marshaling of the keyAuth to return no error")
|
||||
|
||||
@@ -96,6 +96,7 @@ func (s *AccountsStorage) ExistsAccountFilePath() bool {
|
||||
} else if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -127,6 +128,7 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
|
||||
}
|
||||
|
||||
var account Account
|
||||
|
||||
err = json.Unmarshal(fileBytes, &account)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not parse file for account %s: %v", s.userID, err)
|
||||
@@ -141,6 +143,7 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
|
||||
}
|
||||
|
||||
account.Registration = reg
|
||||
|
||||
err = s.Save(&account)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not save account for %s. Registration is nil: %#v", s.userID, err)
|
||||
@@ -163,6 +166,7 @@ func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.Priva
|
||||
}
|
||||
|
||||
log.Printf("Saved key to %s", accKeyPath)
|
||||
|
||||
return privateKey
|
||||
}
|
||||
|
||||
@@ -193,6 +197,7 @@ func generatePrivateKey(file string, keyType certcrypto.KeyType) (crypto.Private
|
||||
defer certOut.Close()
|
||||
|
||||
pemKey := certcrypto.PEMBlock(privateKey)
|
||||
|
||||
err = pem.Encode(certOut, pemKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -211,6 +216,7 @@ func loadPrivateKey(file string) (crypto.PrivateKey, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
@@ -229,5 +235,6 @@ func tryRecoverRegistration(ctx *cli.Context, privateKey crypto.PrivateKey) (*re
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ func (s *CertificatesStorage) ExistsFile(domain, extension string) bool {
|
||||
} else if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -283,6 +284,7 @@ func getCertificateChain(certRes *certificate.Resource) ([]*x509.Certificate, er
|
||||
}
|
||||
|
||||
var certChain []*x509.Certificate
|
||||
|
||||
for chainCertPemBlock != nil {
|
||||
chainCert, err := x509.ParseCertificate(chainCertPemBlock.Bytes)
|
||||
if err != nil {
|
||||
@@ -298,6 +300,7 @@ func getCertificateChain(certRes *certificate.Resource) ([]*x509.Certificate, er
|
||||
|
||||
func getPFXEncoder(pfxFormat string) (*pkcs12.Encoder, error) {
|
||||
var encoder *pkcs12.Encoder
|
||||
|
||||
switch pfxFormat {
|
||||
case "SHA256":
|
||||
encoder = pkcs12.Modern2023
|
||||
@@ -318,5 +321,6 @@ func sanitizedDomain(domain string) string {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return safe
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ func listCertificates(ctx *cli.Context) error {
|
||||
if !names {
|
||||
fmt.Println("No certificates found.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,6 +123,7 @@ func listAccount(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
fmt.Println("Found the following accounts:")
|
||||
|
||||
for _, filename := range matches {
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
@@ -129,6 +131,7 @@ func listAccount(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
var account Account
|
||||
|
||||
err = json.Unmarshal(data, &account)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -39,16 +39,20 @@ func createRenew() *cli.Command {
|
||||
Before: func(ctx *cli.Context) error {
|
||||
// we require either domains or csr, but not both
|
||||
hasDomains := len(ctx.StringSlice(flgDomains)) > 0
|
||||
|
||||
hasCsr := ctx.String(flgCSR) != ""
|
||||
if hasDomains && hasCsr {
|
||||
log.Fatalf("Please specify either --%s/-d or --%s/-c, but not both", flgDomains, flgCSR)
|
||||
}
|
||||
|
||||
if !hasDomains && !hasCsr {
|
||||
log.Fatalf("Please specify --%s/-d (or --%s/-c if you already have a CSR)", flgDomains, flgCSR)
|
||||
}
|
||||
|
||||
if ctx.Bool(flgForceCertDomains) && hasCsr {
|
||||
log.Fatalf("--%s only works with --%s/-d, --%s/-c doesn't support this option.", flgForceCertDomains, flgDomains, flgCSR)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
@@ -165,8 +169,10 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
|
||||
|
||||
cert := certificates[0]
|
||||
|
||||
var ariRenewalTime *time.Time
|
||||
var replacesCertID string
|
||||
var (
|
||||
ariRenewalTime *time.Time
|
||||
replacesCertID string
|
||||
)
|
||||
|
||||
var client *lego.Client
|
||||
|
||||
@@ -208,6 +214,7 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
|
||||
log.Infof("[%s] acme: Trying renewal with %d hours remaining", domain, int(timeLeft.Hours()))
|
||||
|
||||
var privateKey crypto.PrivateKey
|
||||
|
||||
if ctx.Bool(flgReuseKey) {
|
||||
keyBytes, errR := certsStorage.ReadFile(domain, keyExt)
|
||||
if errR != nil {
|
||||
@@ -225,6 +232,7 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
|
||||
if !isatty.IsTerminal(os.Stdout.Fd()) && !ctx.Bool(flgNoRandomSleep) {
|
||||
// https://github.com/certbot/certbot/blob/284023a1b7672be2bd4018dd7623b3b92197d4b0/certbot/certbot/_internal/renewal.py#L472
|
||||
const jitter = 8 * time.Minute
|
||||
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
sleepTime := time.Duration(rnd.Int63n(int64(jitter)))
|
||||
|
||||
@@ -288,8 +296,10 @@ func renewForCSR(ctx *cli.Context, account *Account, keyType certcrypto.KeyType,
|
||||
|
||||
cert := certificates[0]
|
||||
|
||||
var ariRenewalTime *time.Time
|
||||
var replacesCertID string
|
||||
var (
|
||||
ariRenewalTime *time.Time
|
||||
replacesCertID string
|
||||
)
|
||||
|
||||
var client *lego.Client
|
||||
|
||||
@@ -408,16 +418,20 @@ func getARIRenewalTime(ctx *cli.Context, cert *x509.Certificate, domain string,
|
||||
log.Warnf("[%s] acme: %v", domain, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warnf("[%s] acme: calling renewal info endpoint: %v", domain, err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
renewalTime := renewalInfo.ShouldRenewAt(now, ctx.Duration(flgARIWaitToRenewDuration))
|
||||
if renewalTime == nil {
|
||||
log.Infof("[%s] acme: renewalInfo endpoint indicates that renewal is not needed", domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("[%s] acme: renewalInfo endpoint indicates that renewal is needed", domain)
|
||||
|
||||
if renewalInfo.ExplanationURL != "" {
|
||||
|
||||
@@ -35,13 +35,16 @@ func createRun() *cli.Command {
|
||||
Before: func(ctx *cli.Context) error {
|
||||
// we require either domains or csr, but not both
|
||||
hasDomains := len(ctx.StringSlice(flgDomains)) > 0
|
||||
|
||||
hasCsr := ctx.String(flgCSR) != ""
|
||||
if hasDomains && hasCsr {
|
||||
log.Fatal("Please specify either --domains/-d or --csr/-c, but not both")
|
||||
}
|
||||
|
||||
if !hasDomains && !hasCsr {
|
||||
log.Fatal("Please specify --domains/-d (or --csr/-c if you already have a CSR)")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Action: run,
|
||||
@@ -155,10 +158,12 @@ func handleTOS(ctx *cli.Context, client *lego.Client) bool {
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
log.Printf("Please review the TOS at %s", client.GetToSURL())
|
||||
|
||||
for {
|
||||
fmt.Println("Do you accept the TOS? Y/n")
|
||||
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read from console: %v", err)
|
||||
@@ -219,6 +224,7 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso
|
||||
|
||||
if ctx.IsSet(flgPrivateKey) {
|
||||
var err error
|
||||
|
||||
request.PrivateKey, err = loadPrivateKey(ctx.String(flgPrivateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load private key: %w", err)
|
||||
@@ -247,6 +253,7 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso
|
||||
|
||||
if ctx.IsSet(flgPrivateKey) {
|
||||
var err error
|
||||
|
||||
request.PrivateKey, err = loadPrivateKey(ctx.String(flgPrivateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load private key: %w", err)
|
||||
|
||||
@@ -258,5 +258,6 @@ func getTime(ctx *cli.Context, name string) time.Time {
|
||||
if value == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
return *value
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ func launchHook(hook string, timeout time.Duration, meta map[string]string) erro
|
||||
parts := strings.Fields(hook)
|
||||
|
||||
cmd := exec.CommandContext(ctxCmd, parts[0], parts[1:]...)
|
||||
|
||||
cmd.Env = append(os.Environ(), metaToEnv(meta)...)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
@@ -50,6 +51,7 @@ func launchHook(hook string, timeout time.Duration, meta map[string]string) erro
|
||||
|
||||
go func() {
|
||||
<-ctxCmd.Done()
|
||||
|
||||
if ctxCmd.Err() != nil {
|
||||
_ = cmd.Process.Kill()
|
||||
_ = stdout.Close()
|
||||
|
||||
@@ -26,6 +26,7 @@ func main() {
|
||||
}
|
||||
|
||||
var defaultPath string
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err == nil {
|
||||
defaultPath = filepath.Join(cwd, ".lego")
|
||||
|
||||
@@ -114,6 +114,7 @@ func getKeyType(ctx *cli.Context) certcrypto.KeyType {
|
||||
}
|
||||
|
||||
log.Fatalf("Unsupported KeyType: %s", keyType)
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -122,6 +123,7 @@ func getEmail(ctx *cli.Context) string {
|
||||
if email == "" {
|
||||
log.Fatalf("You have to pass an account (email address) to the program using --%s or -m", flgEmail)
|
||||
}
|
||||
|
||||
return email
|
||||
}
|
||||
|
||||
@@ -135,6 +137,7 @@ func createNonExistingFolder(path string) error {
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -143,10 +146,12 @@ func readCSRFile(filename string) (*x509.CertificateRequest, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raw := bytes
|
||||
|
||||
// see if we can find a PEM-encoded CSR
|
||||
var p *pem.Block
|
||||
|
||||
rest := bytes
|
||||
for {
|
||||
// decode a PEM block
|
||||
|
||||
@@ -54,18 +54,21 @@ func setupHTTPProvider(ctx *cli.Context) challenge.Provider {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return ps
|
||||
case ctx.IsSet(flgHTTPMemcachedHost):
|
||||
ps, err := memcached.NewMemcachedProvider(ctx.StringSlice(flgHTTPMemcachedHost))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return ps
|
||||
case ctx.IsSet(flgHTTPS3Bucket):
|
||||
ps, err := s3.NewHTTPProvider(ctx.String(flgHTTPS3Bucket))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return ps
|
||||
case ctx.IsSet(flgHTTPPort):
|
||||
iface := ctx.String(flgHTTPPort)
|
||||
@@ -82,12 +85,14 @@ func setupHTTPProvider(ctx *cli.Context) challenge.Provider {
|
||||
if header := ctx.String(flgHTTPProxyHeader); header != "" {
|
||||
srv.SetProxyHeader(header)
|
||||
}
|
||||
|
||||
return srv
|
||||
case ctx.Bool(flgHTTP):
|
||||
srv := http01.NewProviderServer("", "")
|
||||
if header := ctx.String(flgHTTPProxyHeader); header != "" {
|
||||
srv.SetProxyHeader(header)
|
||||
}
|
||||
|
||||
return srv
|
||||
default:
|
||||
log.Fatal("Invalid HTTP challenge options.")
|
||||
|
||||
@@ -205,6 +205,7 @@ func TestChallengeTLS_Run_Revoke_Non_ASCII(t *testing.T) {
|
||||
func TestChallengeHTTP_Client_Obtain(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -222,6 +223,7 @@ func TestChallengeHTTP_Client_Obtain(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
@@ -243,6 +245,7 @@ func TestChallengeHTTP_Client_Obtain(t *testing.T) {
|
||||
func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -260,6 +263,7 @@ func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
@@ -282,6 +286,7 @@ func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
|
||||
func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -299,6 +304,7 @@ func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
@@ -321,6 +327,7 @@ func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
|
||||
func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -338,6 +345,7 @@ func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
now := time.Now().UTC()
|
||||
@@ -368,6 +376,7 @@ func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
|
||||
func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -385,6 +394,7 @@ func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
resource, err := client.Registration.QueryRegistration()
|
||||
@@ -400,6 +410,7 @@ func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
|
||||
func TestChallengeTLS_Client_Obtain(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -417,6 +428,7 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
// https://github.com/letsencrypt/pebble/issues/285
|
||||
@@ -443,6 +455,7 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
|
||||
func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -460,6 +473,7 @@ func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
csr, err := x509.ParseCertificateRequest(createTestCSR(t))
|
||||
@@ -483,6 +497,7 @@ func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
|
||||
func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -500,6 +515,7 @@ func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
csr, err := x509.ParseCertificateRequest(createTestCSR(t))
|
||||
@@ -524,6 +540,7 @@ func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
|
||||
func TestRegistrar_UpdateAccount(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
|
||||
@@ -75,10 +75,12 @@ func TestChallengeDNS_Run(t *testing.T) {
|
||||
func TestChallengeDNS_Client_Obtain(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "../fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
err = os.Setenv("EXEC_PATH", "../fixtures/update-dns.sh")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("EXEC_PATH") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -101,6 +103,7 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
domains := []string{testDomain2, testDomain1}
|
||||
@@ -129,10 +132,12 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
|
||||
func TestChallengeDNS_Client_Obtain_profile(t *testing.T) {
|
||||
err := os.Setenv("LEGO_CA_CERTIFICATES", "../fixtures/certs/pebble.minica.pem")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
||||
|
||||
err = os.Setenv("EXEC_PATH", "../fixtures/update-dns.sh")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() { _ = os.Unsetenv("EXEC_PATH") }()
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
@@ -155,6 +160,7 @@ func TestChallengeDNS_Client_Obtain_profile(t *testing.T) {
|
||||
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
user.registration = reg
|
||||
|
||||
domains := []string{testDomain2, testDomain1}
|
||||
|
||||
@@ -43,12 +43,14 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
|
||||
if _, e2e := os.LookupEnv("LEGO_E2E_TESTS"); !e2e {
|
||||
fmt.Fprintln(os.Stderr, "skipping test: e2e tests are disabled. (no 'LEGO_E2E_TESTS' env var)")
|
||||
fmt.Println("PASS")
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "skipping because git command not found")
|
||||
fmt.Println("PASS")
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -56,6 +58,7 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
|
||||
if _, err := exec.LookPath(cmdNamePebble); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "skipping because pebble binary not found")
|
||||
fmt.Println("PASS")
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -64,6 +67,7 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
|
||||
if _, err := exec.LookPath(cmdNameChallSrv); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "skipping because challtestsrv binary not found")
|
||||
fmt.Println("PASS")
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -76,6 +80,7 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
|
||||
|
||||
legoBinary, tearDown, err := buildLego()
|
||||
defer tearDown()
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
@@ -136,6 +141,7 @@ func (l *EnvLoader) launchPebble() func() {
|
||||
}
|
||||
|
||||
pebble, outPebble := l.cmdPebble()
|
||||
|
||||
go func() {
|
||||
err := pebble.Run()
|
||||
if err != nil {
|
||||
@@ -148,6 +154,7 @@ func (l *EnvLoader) launchPebble() func() {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
fmt.Println(outPebble.String())
|
||||
}
|
||||
}
|
||||
@@ -160,11 +167,13 @@ func (l *EnvLoader) cmdPebble() (*exec.Cmd, *bytes.Buffer) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cmd.Dir = dir
|
||||
|
||||
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
@@ -173,6 +182,7 @@ func (l *EnvLoader) cmdPebble() (*exec.Cmd, *bytes.Buffer) {
|
||||
|
||||
func pebbleHealthCheck(options *CmdOption) {
|
||||
client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
|
||||
|
||||
err := wait.For("pebble", 10*time.Second, 500*time.Millisecond, func() (bool, error) {
|
||||
resp, err := client.Get(options.HealthCheckURL)
|
||||
if err != nil {
|
||||
@@ -196,6 +206,7 @@ func (l *EnvLoader) launchChallSrv() func() {
|
||||
}
|
||||
|
||||
challtestsrv, outChalSrv := l.cmdChallSrv()
|
||||
|
||||
go func() {
|
||||
err := challtestsrv.Run()
|
||||
if err != nil {
|
||||
@@ -208,6 +219,7 @@ func (l *EnvLoader) launchChallSrv() func() {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
fmt.Println(outChalSrv.String())
|
||||
}
|
||||
}
|
||||
@@ -218,6 +230,7 @@ func (l *EnvLoader) cmdChallSrv() (*exec.Cmd, *bytes.Buffer) {
|
||||
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
@@ -229,6 +242,7 @@ func buildLego() (string, func(), error) {
|
||||
if err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
|
||||
defer func() { _ = os.Chdir(here) }()
|
||||
|
||||
buildPath, err := os.MkdirTemp("", "lego_test")
|
||||
@@ -262,6 +276,7 @@ func buildLego() (string, func(), error) {
|
||||
|
||||
return binary, func() {
|
||||
_ = os.RemoveAll(buildPath)
|
||||
|
||||
CleanLegoFiles()
|
||||
}, nil
|
||||
}
|
||||
@@ -283,6 +298,7 @@ func build(binary string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command(toolPath, "build", "-o", binary)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
@@ -334,6 +350,7 @@ func goTool() (string, error) {
|
||||
func CleanLegoFiles() {
|
||||
cmd := exec.Command("rm", "-rf", ".lego")
|
||||
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(string(output))
|
||||
|
||||
@@ -50,6 +50,7 @@ func generate() error {
|
||||
|
||||
// collect output of various help pages
|
||||
var help []commandHelp
|
||||
|
||||
for _, args := range [][]string{
|
||||
{"lego", "help"},
|
||||
{"lego", "help", "run"},
|
||||
@@ -72,7 +73,9 @@ func generate() error {
|
||||
}
|
||||
|
||||
err = outputTpl.Execute(f, help)
|
||||
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write cli_help.toml: %w", err)
|
||||
}
|
||||
@@ -98,9 +101,11 @@ func createStubApp() *cli.App {
|
||||
|
||||
func run(app *cli.App, args []string) (h commandHelp, err error) {
|
||||
w := app.Writer
|
||||
|
||||
defer func() { app.Writer = w }()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
app.Writer = &buf
|
||||
|
||||
if err := app.Run(args); err != nil {
|
||||
|
||||
@@ -116,6 +116,7 @@ func generateCLIHelp(models *descriptors.Providers) error {
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
err = template.Must(
|
||||
template.New(filepath.Base(cliTemplate)).Funcs(map[string]any{
|
||||
"safe": func(src string) string {
|
||||
@@ -134,6 +135,7 @@ func generateCLIHelp(models *descriptors.Providers) error {
|
||||
}
|
||||
|
||||
_, err = file.Write(source)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -161,6 +163,7 @@ func generateReadMe(models *descriptors.Providers) error {
|
||||
if err = tpl.Execute(buffer, providers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skip = true
|
||||
}
|
||||
|
||||
@@ -198,8 +201,10 @@ func orderProviders(models *descriptors.Providers) [][]descriptors.Provider {
|
||||
return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name))
|
||||
})
|
||||
|
||||
var matrix [][]descriptors.Provider
|
||||
var row []descriptors.Provider
|
||||
var (
|
||||
matrix [][]descriptors.Provider
|
||||
row []descriptors.Provider
|
||||
)
|
||||
|
||||
for i, p := range providers {
|
||||
switch {
|
||||
@@ -212,6 +217,7 @@ func orderProviders(models *descriptors.Providers) [][]descriptors.Provider {
|
||||
for j := len(row); j < nbCol; j++ {
|
||||
row = append(row, descriptors.Provider{})
|
||||
}
|
||||
|
||||
matrix = append(matrix, row)
|
||||
|
||||
default:
|
||||
@@ -223,6 +229,7 @@ func orderProviders(models *descriptors.Providers) [][]descriptors.Provider {
|
||||
for j := len(row); j < nbCol; j++ {
|
||||
row = append(row, descriptors.Provider{})
|
||||
}
|
||||
|
||||
matrix = append(matrix, row)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ func generate() error {
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
err = template.Must(
|
||||
template.New("").Funcs(map[string]any{
|
||||
"cleanName": func(src string) string {
|
||||
|
||||
@@ -108,6 +108,7 @@ func detach(_ *cli.Context) error {
|
||||
|
||||
func readCurrentVersion(filename string) (*hcversion.Version, error) {
|
||||
fset := token.NewFileSet()
|
||||
|
||||
file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -141,6 +142,7 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(valueSpec.Names) != 1 || len(valueSpec.Values) != 1 {
|
||||
continue
|
||||
}
|
||||
@@ -149,6 +151,7 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if va.Kind != token.STRING {
|
||||
continue
|
||||
}
|
||||
@@ -164,6 +167,7 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
|
||||
default:
|
||||
// noop
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
|
||||
5
platform/config/env/env.go
vendored
5
platform/config/env/env.go
vendored
@@ -16,11 +16,13 @@ func Get(names ...string) (map[string]string, error) {
|
||||
values := map[string]string{}
|
||||
|
||||
var missingEnvVars []string
|
||||
|
||||
for _, envVar := range names {
|
||||
value := GetOrFile(envVar)
|
||||
if value == "" {
|
||||
missingEnvVars = append(missingEnvVars, envVar)
|
||||
}
|
||||
|
||||
values[envVar] = value
|
||||
}
|
||||
|
||||
@@ -58,6 +60,7 @@ 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")
|
||||
@@ -68,6 +71,7 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
||||
missingEnvVars = append(missingEnvVars, envVar)
|
||||
continue
|
||||
}
|
||||
|
||||
values[envVar] = value
|
||||
}
|
||||
|
||||
@@ -148,6 +152,7 @@ func GetOrFile(envVar string) string {
|
||||
}
|
||||
|
||||
fileVar := envVar + "_FILE"
|
||||
|
||||
fileVarValue := os.Getenv(fileVar)
|
||||
if fileVarValue == "" {
|
||||
return envVarValue
|
||||
|
||||
@@ -42,6 +42,7 @@ func WriteJSONResponse(w http.ResponseWriter, body any) error {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if _, err := w.Write(bs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ type EnvTest struct {
|
||||
// NewEnvTest Creates an EnvTest.
|
||||
func NewEnvTest(keys ...string) *EnvTest {
|
||||
values := make(map[string]string)
|
||||
|
||||
for _, key := range keys {
|
||||
value := os.Getenv(key)
|
||||
if value != "" {
|
||||
@@ -39,6 +40,7 @@ func NewEnvTest(keys ...string) *EnvTest {
|
||||
func (e *EnvTest) WithDomain(key string) *EnvTest {
|
||||
e.domainKey = key
|
||||
e.domain = os.Getenv(key)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
exitCode := m.Run()
|
||||
|
||||
clearEnv()
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
@@ -39,6 +40,7 @@ func clearEnv() {
|
||||
os.Unsetenv(strings.Split(key, "=")[0])
|
||||
}
|
||||
}
|
||||
|
||||
os.Unsetenv("EXTRA_LEGO_TEST")
|
||||
}
|
||||
|
||||
@@ -325,6 +327,7 @@ func TestEnvTest(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer clearEnv()
|
||||
|
||||
applyEnv(test.envVars)
|
||||
|
||||
envTest := test.envTestSetup()
|
||||
|
||||
@@ -43,6 +43,7 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
|
||||
if len(form) != len(l.values)+len(l.regexes) {
|
||||
msg := fmt.Sprintf("invalid query parameters, got %v, want %v", req.Form, l.values)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -52,6 +53,7 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
|
||||
if !slices.Equal(v, value) {
|
||||
msg := fmt.Sprintf("invalid %q form value, got %q, want %q", k, value, v)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -61,6 +63,7 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
|
||||
if !exp.MatchString(value) {
|
||||
msg := fmt.Sprintf("invalid %q form value, %q doesn't match to %q", k, value, exp)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ func (l *HeaderLink) Bind(next http.Handler) http.Handler {
|
||||
if !exp.MatchString(value) {
|
||||
msg := fmt.Sprintf("invalid %q header value, %q doesn't match to %q", k, value, exp)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
|
||||
if len(query) != len(l.values)+len(l.regexes) {
|
||||
msg := fmt.Sprintf("invalid query parameters, got %v, want %v", query, l.values)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -41,6 +42,7 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
|
||||
if p != v {
|
||||
msg := fmt.Sprintf("invalid %q query parameter value, got %q, want %q", k, p, v)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -50,6 +52,7 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
|
||||
if !exp.MatchString(value) {
|
||||
msg := fmt.Sprintf("invalid %q query parameter value, %q doesn't match to %q", k, value, exp)
|
||||
http.Error(rw, msg, l.statusCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ func (l *RequestBodyLink) Bind(next http.Handler) http.Handler {
|
||||
msg := fmt.Sprintf("%s: request body differences: got: %s, want: %s", req.URL.Path,
|
||||
string(bytes.TrimSpace(body)), string(bytes.TrimSpace(expectedRaw)))
|
||||
http.Error(rw, msg, http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ func (l *RequestBodyJSONLink) Bind(next http.Handler) http.Handler {
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("%s: the expected request body is not valid JSON: %v", req.URL.Path, err)
|
||||
http.Error(rw, msg, http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -97,12 +98,14 @@ func (l *RequestBodyJSONLink) Bind(next http.Handler) http.Handler {
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("%s: request body is not valid JSON: %v", req.URL.Path, err)
|
||||
http.Error(rw, msg, http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !cmp.Equal(actual, expected) {
|
||||
msg := fmt.Sprintf("%s: request body differences: %s", req.URL.Path, cmp.Diff(actual, expected))
|
||||
http.Error(rw, msg, http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,16 @@ func For(msg string, timeout, interval time.Duration, f func() (bool, error)) er
|
||||
log.Infof("Wait for %s [timeout: %s, interval: %s]", msg, timeout, interval)
|
||||
|
||||
var lastErr error
|
||||
|
||||
timeUp := time.After(timeout)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timeUp:
|
||||
if lastErr == nil {
|
||||
return fmt.Errorf("%s: time limit exceeded", msg)
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s: time limit exceeded: last error: %w", msg, lastErr)
|
||||
default:
|
||||
}
|
||||
@@ -44,5 +47,6 @@ func Retry(ctx context.Context, operation func() error, opts ...backoff.RetryOpt
|
||||
_, err := backoff.Retry(ctx, func() (any, error) {
|
||||
return nil, operation()
|
||||
}, opts...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ func TestFor_timeout(t *testing.T) {
|
||||
go func() {
|
||||
c <- For("test", 3*time.Second, 1*time.Second, func() (bool, error) {
|
||||
io.Add(1)
|
||||
|
||||
if io.Load() == 1 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
}
|
||||
|
||||
// NewDNSProviderClient creates an ACME-DNS DNSProvider with the given acmeDNSClient and [goacmedns.Storage].
|
||||
//
|
||||
// Deprecated: use [NewDNSProviderConfig] instead.
|
||||
func NewDNSProviderClient(client acmeDNSClient, store goacmedns.Storage) (*DNSProvider, error) {
|
||||
if client == nil {
|
||||
|
||||
@@ -107,6 +107,7 @@ func newMockStorage() *mockStorage {
|
||||
if acct, ok := m.accounts[domain]; ok {
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
return goacmedns.Account{}, storage.ErrDomainNotFound
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -124,6 +125,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -137,6 +139,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("alicloud: API call failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -233,6 +234,7 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string,
|
||||
}
|
||||
|
||||
var hostedZone *alidns.DescribeDomainsResponseBodyDomainsDomain
|
||||
|
||||
for _, zone := range domains {
|
||||
if ptr.Deref(zone.DomainName) == dns01.UnFqdn(authZone) || ptr.Deref(zone.PunyCode) == dns01.UnFqdn(authZone) {
|
||||
hostedZone = zone
|
||||
@@ -287,6 +289,7 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]*alidn
|
||||
records = append(records, record)
|
||||
}
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -142,6 +143,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -155,6 +157,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
d.recordIDsMu.Lock()
|
||||
recordID, ok := d.recordIDs[token]
|
||||
d.recordIDsMu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("allinkl: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -121,6 +122,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -134,6 +136,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ func (c *Client) GetDNSSettings(ctx context.Context, zone, recordID string) ([]R
|
||||
}
|
||||
|
||||
var g GetDNSSettingsAPIResponse
|
||||
|
||||
err = c.do(req, &g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -75,6 +76,7 @@ func (c *Client) AddDNSSettings(ctx context.Context, record DNSRequest) (string,
|
||||
}
|
||||
|
||||
var g AddDNSSettingsAPIResponse
|
||||
|
||||
err = c.do(req, &g)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -95,6 +97,7 @@ func (c *Client) DeleteDNSSettings(ctx context.Context, recordID string) (string
|
||||
}
|
||||
|
||||
var g DeleteDNSSettingsAPIResponse
|
||||
|
||||
err = c.do(req, &g)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -17,6 +17,7 @@ func (tr Trimmer) Token() (xml.Token, error) {
|
||||
if cd, ok := t.(xml.CharData); ok {
|
||||
t = xml.CharData(bytes.TrimSpace(cd))
|
||||
}
|
||||
|
||||
return t, err
|
||||
}
|
||||
|
||||
@@ -53,6 +54,7 @@ func decodeXML[T any](reader io.Reader) (*T, error) {
|
||||
}
|
||||
|
||||
var result T
|
||||
|
||||
err = xml.NewTokenDecoder(Trimmer{decoder: xml.NewDecoder(bytes.NewReader(raw))}).Decode(&result)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode XML response: %w", err)
|
||||
|
||||
@@ -96,6 +96,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
|
||||
if config.APIURL != "" {
|
||||
var err error
|
||||
|
||||
client.BaseURL, err = url.Parse(config.APIURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("anexia: %w", err)
|
||||
|
||||
@@ -42,6 +42,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -102,6 +103,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -115,6 +117,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ func (c *Client) CreateRecord(ctx context.Context, zoneName string, record Recor
|
||||
}
|
||||
|
||||
var zone Zone
|
||||
|
||||
err = c.do(req, &zone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -147,6 +148,7 @@ func parseError(req *http.Request, resp *http.Response) error {
|
||||
raw, _ := io.ReadAll(resp.Body)
|
||||
|
||||
var errAPI APIError
|
||||
|
||||
err := json.Unmarshal(raw, &errAPI)
|
||||
if err != nil {
|
||||
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
|
||||
|
||||
@@ -167,6 +167,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
d.recordIDsMu.Lock()
|
||||
recordID, ok := d.recordIDs[token]
|
||||
d.recordIDsMu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("arvancloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -104,6 +105,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -117,6 +119,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ func (c *Client) getRecords(ctx context.Context, domain, search string) ([]DNSRe
|
||||
}
|
||||
|
||||
response := &apiResponse[[]DNSRecord]{}
|
||||
|
||||
err = c.do(req, http.StatusOK, response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get records %s: Domain: %s: %w", search, domain, err)
|
||||
@@ -89,6 +90,7 @@ func (c *Client) CreateRecord(ctx context.Context, domain string, record DNSReco
|
||||
}
|
||||
|
||||
response := &apiResponse[*DNSRecord]{}
|
||||
|
||||
err = c.do(req, http.StatusCreated, response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create record; Domain: %s: %w", domain, err)
|
||||
|
||||
@@ -81,8 +81,10 @@ func TestClient_CreateRecord(t *testing.T) {
|
||||
func TestClient_DeleteRecord(t *testing.T) {
|
||||
const apiKey = "myKeyC"
|
||||
|
||||
const domain = "example.com"
|
||||
const recordID = "recordId"
|
||||
const (
|
||||
domain = "example.com"
|
||||
recordID = "recordId"
|
||||
)
|
||||
|
||||
client := mockBuilder(apiKey).
|
||||
Route("DELETE /cdn/4.0/domains/"+domain+"/dns-records/"+recordID, nil).
|
||||
|
||||
@@ -71,6 +71,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
|
||||
@@ -57,6 +57,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -131,6 +132,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -144,6 +146,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ func (c *Client) RemoveTXTRecords(ctx context.Context, domain string, records []
|
||||
zoneStream := &ZoneStream{Removes: records}
|
||||
|
||||
_, err := c.updateZone(ctx, domain, zoneStream)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -120,6 +121,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -133,6 +135,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ func parseError(req *http.Request, resp *http.Response) error {
|
||||
raw, _ := io.ReadAll(resp.Body)
|
||||
|
||||
var errAPI APIError
|
||||
|
||||
err := json.Unmarshal(raw, &errAPI)
|
||||
if err != nil {
|
||||
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
|
||||
|
||||
@@ -137,6 +137,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
record.SetTtl(int32(d.config.TTL))
|
||||
|
||||
var resp *idns.PostOrPutRecordResponse
|
||||
|
||||
if existingRecord != nil {
|
||||
// Update existing record by adding the new value to the existing ones
|
||||
record.SetAnswersList(append(existingRecord.GetAnswersList(), info.Value))
|
||||
@@ -161,6 +162,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
}
|
||||
|
||||
results := resp.GetResults()
|
||||
|
||||
d.recordIDsMu.Lock()
|
||||
d.recordIDs[token] = results.GetId()
|
||||
d.recordIDsMu.Unlock()
|
||||
@@ -203,6 +205,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
currentAnswers := existingRecord.GetAnswersList()
|
||||
|
||||
var updatedAnswers []string
|
||||
|
||||
for _, answer := range currentAnswers {
|
||||
if answer != info.Value {
|
||||
updatedAnswers = append(updatedAnswers, answer)
|
||||
|
||||
@@ -40,6 +40,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -99,6 +100,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -112,6 +114,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ type DNSProvider struct {
|
||||
// If the credentials are _not_ set via the environment,
|
||||
// then it will attempt to get a bearer token via the instance metadata service.
|
||||
// see: https://github.com/Azure/go-autorest/blob/v10.14.0/autorest/azure/auth/auth.go#L38-L42
|
||||
//
|
||||
// Deprecated: use azuredns instead.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
config := NewDefaultConfig()
|
||||
@@ -96,6 +97,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
||||
environmentName := env.GetOrFile(EnvEnvironment)
|
||||
if environmentName != "" {
|
||||
var environment aazure.Environment
|
||||
|
||||
switch environmentName {
|
||||
case "china":
|
||||
environment = aazure.ChinaCloud
|
||||
@@ -124,6 +126,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
||||
}
|
||||
|
||||
// NewDNSProviderConfig return a DNSProvider instance configured for Azure.
|
||||
//
|
||||
// Deprecated: use azuredns instead.
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
@@ -148,6 +151,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if subsID == "" {
|
||||
return nil, errors.New("azure: SubscriptionID is missing")
|
||||
}
|
||||
|
||||
config.SubscriptionID = subsID
|
||||
}
|
||||
|
||||
@@ -160,6 +164,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if resGroup == "" {
|
||||
return nil, errors.New("azure: ResourceGroup is missing")
|
||||
}
|
||||
|
||||
config.ResourceGroup = resGroup
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -158,6 +159,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
|
||||
} else {
|
||||
mux.HandleFunc("/", test.handler)
|
||||
}
|
||||
|
||||
config.MetadataEndpoint = server.URL
|
||||
|
||||
p, err := NewDNSProviderConfig(config)
|
||||
@@ -186,6 +188,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -199,6 +202,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ func (d *dnsProviderPrivate) Present(domain, token, keyAuth string) error {
|
||||
|
||||
// Construct unique TXT records using map
|
||||
uniqRecords := map[string]struct{}{info.Value: {}}
|
||||
|
||||
if rset.RecordSetProperties != nil && rset.TxtRecords != nil {
|
||||
for _, txtRecord := range *rset.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
@@ -81,6 +82,7 @@ func (d *dnsProviderPrivate) Present(domain, token, keyAuth string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("azure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,6 +108,7 @@ func (d *dnsProviderPrivate) CleanUp(domain, token, keyAuth string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("azure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ func (d *dnsProviderPublic) Present(domain, token, keyAuth string) error {
|
||||
|
||||
// Construct unique TXT records using map
|
||||
uniqRecords := map[string]struct{}{info.Value: {}}
|
||||
|
||||
if rset.RecordSetProperties != nil && rset.TxtRecords != nil {
|
||||
for _, txtRecord := range *rset.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
@@ -81,6 +82,7 @@ func (d *dnsProviderPublic) Present(domain, token, keyAuth string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("azure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,6 +108,7 @@ func (d *dnsProviderPublic) CleanUp(domain, token, keyAuth string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("azure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
@@ -61,6 +62,7 @@ func TestLivePresent(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -74,6 +76,7 @@ func TestLiveCleanUp(t *testing.T) {
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ func getCredentials(config *Config) (azcore.TokenCredential, error) {
|
||||
if config.TenantID != "" {
|
||||
credOptions = &azidentity.AzureCLICredentialOptions{TenantID: config.TenantID}
|
||||
}
|
||||
|
||||
return azidentity.NewAzureCLICredential(credOptions)
|
||||
|
||||
case authMethodOIDC:
|
||||
|
||||
@@ -181,6 +181,7 @@ func (c privateZoneClient) Delete(ctx context.Context, subDomain string) (armpri
|
||||
|
||||
func privateUniqueRecords(recordSet armprivatedns.RecordSet, value string) map[string]struct{} {
|
||||
uniqRecords := map[string]struct{}{value: {}}
|
||||
|
||||
if recordSet.Properties != nil && recordSet.Properties.TxtRecords != nil {
|
||||
for _, txtRecord := range recordSet.Properties.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
|
||||
@@ -179,6 +179,7 @@ func (c publicZoneClient) Delete(ctx context.Context, subDomain string) (armdns.
|
||||
|
||||
func publicUniqueRecords(recordSet armdns.RecordSet, value string) map[string]struct{} {
|
||||
uniqRecords := map[string]struct{}{value: {}}
|
||||
|
||||
if recordSet.Properties != nil && recordSet.Properties.TxtRecords != nil {
|
||||
for _, txtRecord := range recordSet.Properties.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
|
||||
@@ -46,6 +46,7 @@ func discoverDNSZones(ctx context.Context, config *Config, credentials azcore.To
|
||||
}
|
||||
|
||||
zones := map[string]ServiceDiscoveryZone{}
|
||||
|
||||
for {
|
||||
// create the query request
|
||||
request := armresourcegraph.QueryRequest{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user