http_challenge.go raw
1 package http01
2
3 import (
4 "fmt"
5 "time"
6
7 "github.com/go-acme/lego/v4/acme"
8 "github.com/go-acme/lego/v4/acme/api"
9 "github.com/go-acme/lego/v4/challenge"
10 "github.com/go-acme/lego/v4/log"
11 )
12
13 type ValidateFunc func(core *api.Core, domain string, chlng acme.Challenge) error
14
15 type ChallengeOption func(*Challenge) error
16
17 // SetDelay sets a delay between the start of the HTTP server and the challenge validation.
18 func SetDelay(delay time.Duration) ChallengeOption {
19 return func(chlg *Challenge) error {
20 chlg.delay = delay
21 return nil
22 }
23 }
24
25 // ChallengePath returns the URL path for the `http-01` challenge.
26 func ChallengePath(token string) string {
27 return "/.well-known/acme-challenge/" + token
28 }
29
30 type Challenge struct {
31 core *api.Core
32 validate ValidateFunc
33 provider challenge.Provider
34 delay time.Duration
35 }
36
37 func NewChallenge(core *api.Core, validate ValidateFunc, provider challenge.Provider, opts ...ChallengeOption) *Challenge {
38 chlg := &Challenge{
39 core: core,
40 validate: validate,
41 provider: provider,
42 }
43
44 for _, opt := range opts {
45 err := opt(chlg)
46 if err != nil {
47 log.Infof("challenge option error: %v", err)
48 }
49 }
50
51 return chlg
52 }
53
54 func (c *Challenge) SetProvider(provider challenge.Provider) {
55 c.provider = provider
56 }
57
58 func (c *Challenge) Solve(authz acme.Authorization) error {
59 domain := challenge.GetTargetedDomain(authz)
60 log.Infof("[%s] acme: Trying to solve HTTP-01", domain)
61
62 chlng, err := challenge.FindChallenge(challenge.HTTP01, authz)
63 if err != nil {
64 return err
65 }
66
67 // Generate the Key Authorization for the challenge
68 keyAuth, err := c.core.GetKeyAuthorization(chlng.Token)
69 if err != nil {
70 return err
71 }
72
73 err = c.provider.Present(authz.Identifier.Value, chlng.Token, keyAuth)
74 if err != nil {
75 return fmt.Errorf("[%s] acme: error presenting token: %w", domain, err)
76 }
77
78 defer func() {
79 err := c.provider.CleanUp(authz.Identifier.Value, chlng.Token, keyAuth)
80 if err != nil {
81 log.Warnf("[%s] acme: cleaning up failed: %v", domain, err)
82 }
83 }()
84
85 if c.delay > 0 {
86 time.Sleep(c.delay)
87 }
88
89 chlng.KeyAuthorization = keyAuth
90
91 return c.validate(c.core, domain, chlng)
92 }
93