diff --git a/pkg/certmanager/acme.go b/pkg/certmanager/acme.go index bc15df2e5..9475077cc 100644 --- a/pkg/certmanager/acme.go +++ b/pkg/certmanager/acme.go @@ -21,6 +21,7 @@ import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "errors" "fmt" "net/http" "time" @@ -57,6 +58,10 @@ type ( } ) +// ErrHTTPChallengeRequired indicates that an HTTP-01 challenge needs to be +// completed before the certificate can be issued or renewed. +var ErrHTTPChallengeRequired = errors.New("HTTP challenge required") + func NewACMEService(email string, keyType keys.Type, directoryURL string, insecureTLS bool, logger *log.Logger) (*ACMEService, error) { accountKey, err := keys.Generate(keyType) if err != nil { @@ -229,7 +234,7 @@ func (s *ACMEService) ObtainCertificate( // The challenge token and key auth will be stored and served via HTTP // The caller is responsible for ensuring the HTTP endpoint is ready // before calling CompleteHTTPChallenge - return nil, fmt.Errorf("HTTP challenge ready: token=%s", challenge.Token) + return nil, fmt.Errorf("%w: token=%s", ErrHTTPChallengeRequired, challenge.Token) } func (s *ACMEService) RenewCertificate( diff --git a/pkg/certmanager/renewer.go b/pkg/certmanager/renewer.go index 4607be2c4..da334fe25 100644 --- a/pkg/certmanager/renewer.go +++ b/pkg/certmanager/renewer.go @@ -16,8 +16,8 @@ package certmanager import ( "context" + "errors" "fmt" - "strings" "time" "github.com/getprobo/probo/pkg/coredata" @@ -146,33 +146,33 @@ func (r *Renewer) renewDomain(ctx context.Context, conn pg.Conn, domain *coredat } cert, err := r.acmeService.RenewCertificate(ctx, lockedDomain.Domain) - if err != nil && strings.Contains(err.Error(), "HTTP challenge ready") { - challenge, err := r.acmeService.GetHTTPChallenge(ctx, lockedDomain.Domain) - if err != nil { - return fmt.Errorf("cannot get HTTP challenge for renewal: %w", err) - } - - r.logger.WarnCtx( - ctx, - "HTTP challenge required for renewal", - log.String("domain", lockedDomain.Domain), - log.String("token", challenge.Token), - ) - - lockedDomain.HTTPChallengeToken = &challenge.Token - lockedDomain.HTTPChallengeKeyAuth = &challenge.KeyAuth - lockedDomain.HTTPChallengeURL = &challenge.URL - lockedDomain.HTTPOrderURL = &challenge.OrderURL - lockedDomain.SSLStatus = coredata.CustomDomainSSLStatusRenewing - - if err := lockedDomain.Update(ctx, conn, scope, r.encryptionKey); err != nil { - return fmt.Errorf("cannot update domain with renewal challenge: %w", err) - } - - return nil - } - if err != nil { + if errors.Is(err, ErrHTTPChallengeRequired) { + challenge, err := r.acmeService.GetHTTPChallenge(ctx, lockedDomain.Domain) + if err != nil { + return fmt.Errorf("cannot get HTTP challenge for renewal: %w", err) + } + + r.logger.WarnCtx( + ctx, + "HTTP challenge required for renewal", + log.String("domain", lockedDomain.Domain), + log.String("token", challenge.Token), + ) + + lockedDomain.HTTPChallengeToken = &challenge.Token + lockedDomain.HTTPChallengeKeyAuth = &challenge.KeyAuth + lockedDomain.HTTPChallengeURL = &challenge.URL + lockedDomain.HTTPOrderURL = &challenge.OrderURL + lockedDomain.SSLStatus = coredata.CustomDomainSSLStatusRenewing + + if err := lockedDomain.Update(ctx, conn, scope, r.encryptionKey); err != nil { + return fmt.Errorf("cannot update domain with renewal challenge: %w", err) + } + + return nil + } + return fmt.Errorf("cannot renew certificate: %w", err) }