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