diff --git a/challenge/resolver/solver_manager.go b/challenge/resolver/solver_manager.go index 95db0af5..dcde3a3e 100644 --- a/challenge/resolver/solver_manager.go +++ b/challenge/resolver/solver_manager.go @@ -42,8 +42,8 @@ func (c *SolverManager) SetHTTP01Provider(p challenge.Provider, opts ...http01.C } // SetTLSALPN01Provider specifies a custom provider p that can solve the given TLS-ALPN-01 challenge. -func (c *SolverManager) SetTLSALPN01Provider(p challenge.Provider) error { - c.solvers[challenge.TLSALPN01] = tlsalpn01.NewChallenge(c.core, validate, p) +func (c *SolverManager) SetTLSALPN01Provider(p challenge.Provider, opts ...tlsalpn01.ChallengeOption) error { + c.solvers[challenge.TLSALPN01] = tlsalpn01.NewChallenge(c.core, validate, p, opts...) return nil } diff --git a/challenge/tlsalpn01/tls_alpn_challenge.go b/challenge/tlsalpn01/tls_alpn_challenge.go index 04ba7150..559e1f90 100644 --- a/challenge/tlsalpn01/tls_alpn_challenge.go +++ b/challenge/tlsalpn01/tls_alpn_challenge.go @@ -7,6 +7,7 @@ import ( "crypto/x509/pkix" "encoding/asn1" "fmt" + "time" "github.com/go-acme/lego/v4/acme" "github.com/go-acme/lego/v4/acme/api" @@ -21,18 +22,38 @@ var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31} type ValidateFunc func(core *api.Core, domain string, chlng acme.Challenge) error +type ChallengeOption func(*Challenge) error + +// SetDelay sets a delay between the start of the TLS listener and the challenge validation. +func SetDelay(delay time.Duration) ChallengeOption { + return func(chlg *Challenge) error { + chlg.delay = delay + return nil + } +} + type Challenge struct { core *api.Core validate ValidateFunc provider challenge.Provider + delay time.Duration } -func NewChallenge(core *api.Core, validate ValidateFunc, provider challenge.Provider) *Challenge { - return &Challenge{ +func NewChallenge(core *api.Core, validate ValidateFunc, provider challenge.Provider, opts ...ChallengeOption) *Challenge { + chlg := &Challenge{ core: core, validate: validate, provider: provider, } + + for _, opt := range opts { + err := opt(chlg) + if err != nil { + log.Infof("challenge option error: %v", err) + } + } + + return chlg } func (c *Challenge) SetProvider(provider challenge.Provider) { @@ -66,6 +87,10 @@ func (c *Challenge) Solve(authz acme.Authorization) error { } }() + if c.delay > 0 { + time.Sleep(c.delay) + } + chlng.KeyAuthorization = keyAuth return c.validate(c.core, domain, chlng) } diff --git a/cmd/flags.go b/cmd/flags.go index 51aa479b..ebf051ae 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -32,6 +32,7 @@ const ( flgHTTPS3Bucket = "http.s3-bucket" flgTLS = "tls" flgTLSPort = "tls.port" + flgTLSDelay = "tls.delay" flgDNS = "dns" flgDNSDisableCP = "dns.disable-cp" flgDNSPropagationWait = "dns.propagation-wait" @@ -164,6 +165,11 @@ func CreateFlags(defaultPath string) []cli.Flag { Usage: "Set the port and interface to use for TLS-ALPN-01 based challenges to listen on. Supported: interface:port or :port.", Value: ":443", }, + &cli.DurationFlag{ + Name: flgTLSDelay, + Usage: "Delay between the start of the TLS listener (use for TLSALPN-01 based challenges) and the validation of the challenge.", + Value: 0, + }, &cli.StringFlag{ Name: flgDNS, Usage: "Solve a DNS-01 challenge using the specified provider. Can be mixed with other types of challenges. Run 'lego dnshelp' for help on usage.", diff --git a/cmd/setup_challenges.go b/cmd/setup_challenges.go index 16a5b90f..c923fa00 100644 --- a/cmd/setup_challenges.go +++ b/cmd/setup_challenges.go @@ -32,7 +32,7 @@ func setupChallenges(ctx *cli.Context, client *lego.Client) { } if ctx.Bool(flgTLS) { - err := client.Challenge.SetTLSALPN01Provider(setupTLSProvider(ctx)) + err := client.Challenge.SetTLSALPN01Provider(setupTLSProvider(ctx), tlsalpn01.SetDelay(ctx.Duration(flgTLSDelay))) if err != nil { log.Fatal(err) } diff --git a/docs/data/zz_cli_help.toml b/docs/data/zz_cli_help.toml index da083666..9b3dd1d0 100644 --- a/docs/data/zz_cli_help.toml +++ b/docs/data/zz_cli_help.toml @@ -39,6 +39,7 @@ GLOBAL OPTIONS: --http.s3-bucket value Set the S3 bucket name to use for HTTP-01 based challenges. Challenges will be written to the S3 bucket. --tls Use the TLS-ALPN-01 challenge to solve challenges. Can be mixed with other types of challenges. (default: false) --tls.port value Set the port and interface to use for TLS-ALPN-01 based challenges to listen on. Supported: interface:port or :port. (default: ":443") + --tls.delay value Delay between the start of the TLS listener (use for TLSALPN-01 based challenges) and the validation of the challenge. (default: 0s) --dns value Solve a DNS-01 challenge using the specified provider. Can be mixed with other types of challenges. Run 'lego dnshelp' for help on usage. --dns.disable-cp (deprecated) use dns.propagation-disable-ans instead. (default: false) --dns.propagation-disable-ans By setting this flag to true, disables the need to await propagation of the TXT record to all authoritative name servers. (default: false)