|  | @ -5,10 +5,12 @@ import ( | 
			
		
	
		
		
			
				
					|  |  | 	"encoding/json" |  |  | 	"encoding/json" | 
			
		
	
		
		
			
				
					|  |  | 	"fmt" |  |  | 	"fmt" | 
			
		
	
		
		
			
				
					|  |  | 	"net/http" |  |  | 	"net/http" | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	"time" | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 	"github.com/caddyserver/caddy" |  |  | 	"github.com/caddyserver/caddy" | 
			
		
	
		
		
			
				
					|  |  | 	"github.com/go-acme/lego/challenge" |  |  | 	"github.com/go-acme/lego/challenge" | 
			
		
	
		
		
			
				
					|  |  | 	"github.com/mholt/certmagic" |  |  | 	"github.com/mholt/certmagic" | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	"golang.org/x/time/rate" | 
			
		
	
		
		
			
				
					|  |  | ) |  |  | ) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | func init() { |  |  | func init() { | 
			
		
	
	
		
		
			
				
					|  | @ -71,6 +73,16 @@ func (t *TLS) Provision(ctx caddy.Context) error { | 
			
		
	
		
		
			
				
					|  |  | 		return fmt.Errorf("provisioning session tickets configuration: %v", err) |  |  | 		return fmt.Errorf("provisioning session tickets configuration: %v", err) | 
			
		
	
		
		
			
				
					|  |  | 	} |  |  | 	} | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	// on-demand rate limiting
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	if t.Automation.OnDemand != nil && t.Automation.OnDemand.RateLimit != nil { | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		limit := rate.Every(time.Duration(t.Automation.OnDemand.RateLimit.Interval)) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// TODO: Burst size is not updated, see https://github.com/golang/go/issues/23575
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		onDemandRateLimiter.SetLimit(limit) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	} else { | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// if no rate limit is specified, be sure to remove any existing limit
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		onDemandRateLimiter.SetLimit(0) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 	return nil |  |  | 	return nil | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -178,6 +190,7 @@ type CertificateLoader interface { | 
			
		
	
		
		
			
				
					|  |  | // construction and use of ACME clients.
 |  |  | // construction and use of ACME clients.
 | 
			
		
	
		
		
			
				
					|  |  | type AutomationConfig struct { |  |  | type AutomationConfig struct { | 
			
		
	
		
		
			
				
					|  |  | 	Policies []AutomationPolicy `json:"policies,omitempty"` |  |  | 	Policies []AutomationPolicy `json:"policies,omitempty"` | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	OnDemand *OnDemandConfig    `json:"on_demand,omitempty"` | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | // AutomationPolicy designates the policy for automating the
 |  |  | // AutomationPolicy designates the policy for automating the
 | 
			
		
	
	
		
		
			
				
					|  | @ -189,6 +202,9 @@ type AutomationPolicy struct { | 
			
		
	
		
		
			
				
					|  |  | 	Management managerMaker `json:"-"` |  |  | 	Management managerMaker `json:"-"` | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | // makeCertMagicConfig converts ap into a CertMagic config. Passing onDemand
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | // is necessary because the automation policy does not have convenient access
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | // to the TLS app's global on-demand policies;
 | 
			
		
	
		
		
			
				
					|  |  | func (ap AutomationPolicy) makeCertMagicConfig(ctx caddy.Context) certmagic.Config { |  |  | func (ap AutomationPolicy) makeCertMagicConfig(ctx caddy.Context) certmagic.Config { | 
			
		
	
		
		
			
				
					|  |  | 	// default manager (ACME) is a special case because of how CertMagic is designed
 |  |  | 	// default manager (ACME) is a special case because of how CertMagic is designed
 | 
			
		
	
		
		
			
				
					|  |  | 	// TODO: refactor certmagic so that ACME manager is not a special case by extracting
 |  |  | 	// TODO: refactor certmagic so that ACME manager is not a special case by extracting
 | 
			
		
	
	
		
		
			
				
					|  | @ -226,10 +242,14 @@ type TLSALPNChallengeConfig struct { | 
			
		
	
		
		
			
				
					|  |  | // OnDemandConfig configures on-demand TLS, for obtaining
 |  |  | // OnDemandConfig configures on-demand TLS, for obtaining
 | 
			
		
	
		
		
			
				
					|  |  | // needed certificates at handshake-time.
 |  |  | // needed certificates at handshake-time.
 | 
			
		
	
		
		
			
				
					|  |  | type OnDemandConfig struct { |  |  | type OnDemandConfig struct { | 
			
		
	
		
		
			
				
					
					|  |  | 	// TODO: MaxCertificates state might not endure reloads...
 |  |  | 	RateLimit *RateLimit `json:"rate_limit,omitempty"` | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 	// MaxCertificates int    `json:"max_certificates,omitempty"`
 |  |  | 	Ask       string     `json:"ask,omitempty"` | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 	AskURL      string `json:"ask_url,omitempty"` |  |  | } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 	AskStarlark string `json:"ask_starlark,omitempty"` |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  | // RateLimit specifies an interval with optional burst size.
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | type RateLimit struct { | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	Interval caddy.Duration `json:"interval,omitempty"` | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	Burst    int            `json:"burst,omitempty"` | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | // managerMaker makes a certificate manager.
 |  |  | // managerMaker makes a certificate manager.
 | 
			
		
	
	
		
		
			
				
					|  | @ -237,4 +257,15 @@ type managerMaker interface { | 
			
		
	
		
		
			
				
					|  |  | 	newManager(interactive bool) (certmagic.Manager, error) |  |  | 	newManager(interactive bool) (certmagic.Manager, error) | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | // These perpetual values are used for on-demand TLS.
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | var ( | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	onDemandRateLimiter = rate.NewLimiter(0, 1) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	onDemandAskClient   = &http.Client{ | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		Timeout: 10 * time.Second, | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		CheckRedirect: func(req *http.Request, via []*http.Request) error { | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 			return fmt.Errorf("following http redirects is not allowed") | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		}, | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					|  |  |  |  |  | ) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | const automateKey = "automate" |  |  | const automateKey = "automate" | 
			
		
	
	
		
		
			
				
					|  | 
 |