fix application bug

This commit is contained in:
Jeff
2019-05-13 11:19:18 +08:00
committed by zryfish
parent 996d6fe4c5
commit 5462f51e65
717 changed files with 87703 additions and 53426 deletions

View File

@@ -20,11 +20,11 @@ import (
"sync"
"time"
"github.com/xenolf/lego/certcrypto"
"github.com/xenolf/lego/certificate"
"github.com/xenolf/lego/challenge"
"github.com/xenolf/lego/challenge/tlsalpn01"
"github.com/xenolf/lego/lego"
"github.com/go-acme/lego/certcrypto"
"github.com/go-acme/lego/certificate"
"github.com/go-acme/lego/challenge"
"github.com/go-acme/lego/challenge/tlsalpn01"
"github.com/go-acme/lego/lego"
)
// Config configures a certificate manager instance.
@@ -74,7 +74,7 @@ type Config struct {
ListenHost string
// The alternate port to use for the ACME HTTP
// challenge; if non-empty, this port will be
// challenge; if non-empty, this port will be
// used instead of HTTPChallengePort to spin up
// a listener for the HTTP challenge
AltHTTPPort int
@@ -113,117 +113,167 @@ type Config struct {
// CSR generated by lego/acme
MustStaple bool
// Map of hostname to certificate hash; used
// to complete handshakes and serve the right
// certificate given SNI
certificates map[string]string
// The storage to access when storing or
// loading TLS assets
Storage Storage
// Pointer to the certificate store to use
// NewManager returns a new Manager. If nil,
// an ACME client will be created and used.
NewManager func(interactive bool) (Manager, error)
// Pointer to the in-memory certificate cache
certCache *Cache
// Map of client config key to ACME clients
// so they can be reused
// TODO: It might be better if these were globally cached, rather than per-config, which are ephemeral... but maybe evict them after a certain time, like 1 day or something
acmeClients map[string]*lego.Client
acmeClientsMu *sync.Mutex
}
// NewDefault returns a new, valid, default config.
// NewDefault makes a valid config based on the package
// Default config. Most users will call this function
// instead of New() since most use cases require only a
// single config for any and all certificates.
//
// Calling this function signifies your acceptance to
// the CA's Subscriber Agreement and/or Terms of Service.
// If your requirements are more advanced (for example,
// multiple configs depending on the certificate), then use
// New() instead. (You will need to make your own Cache
// first.) If you only need a single Config to manage your
// certs (even if that config changes, as long as it is the
// only one), customize the Default package variable before
// calling NewDefault().
//
// All calls to NewDefault() will return configs that use the
// same, default certificate cache. All configs returned
// by NewDefault() are based on the values of the fields of
// Default at the time it is called.
func NewDefault() *Config {
return New(Config{Agreed: true})
}
// New makes a valid config based on cfg and uses
// a default certificate cache. All calls to
// New() will use the same certificate cache.
func New(cfg Config) *Config {
return NewWithCache(nil, cfg)
}
// NewWithCache makes a valid new config based on cfg
// and uses the provided certificate cache. If certCache
// is nil, a new, default one will be created using
// DefaultStorage; or, if a default cache has already
// been created, it will be reused.
func NewWithCache(certCache *Cache, cfg Config) *Config {
// avoid nil pointers with sensible defaults,
// careful to initialize a default cache (which
// begins its maintenance goroutine) only if
// needed - and only once (we don't initialize
// it at package init to give importers a chance
// to set DefaultStorage if they so desire)
if certCache == nil {
defaultCacheMu.Lock()
if defaultCache == nil {
defaultCache = NewCache(DefaultStorage)
}
certCache = defaultCache
defaultCacheMu.Unlock()
defaultCacheMu.Lock()
if defaultCache == nil {
defaultCache = NewCache(CacheOptions{
// the cache will likely need to renew certificates,
// so it will need to know how to do that, which
// depends on the certificate being managed and which
// can change during the lifetime of the cache; this
// callback makes it possible to get the latest and
// correct config with which to manage the cert,
// but if the user does not provide one, we can only
// assume that we are to use the default config
GetConfigForCert: func(Certificate) (Config, error) {
return Default, nil
},
})
}
if certCache.storage == nil {
certCache.storage = DefaultStorage
certCache := defaultCache
defaultCacheMu.Unlock()
return newWithCache(certCache, Default)
}
// New makes a new, valid config based on cfg and
// uses the provided certificate cache. certCache
// MUST NOT be nil or this function will panic.
//
// Use this method when you have an advanced use case
// that requires a custom certificate cache and config
// that may differ from the Default. For example, if
// not all certificates are managed/renewed the same
// way, you need to make your own Cache value with a
// GetConfigForCert callback that returns the correct
// configuration for each certificate. However, for
// the vast majority of cases, there will be only a
// single Config, thus the default cache (which always
// uses the default Config) and default config will
// suffice, and you should use New() instead.
func New(certCache *Cache, cfg Config) *Config {
if certCache == nil {
panic("a certificate cache is required")
}
if certCache.options.GetConfigForCert == nil {
panic("cache must have GetConfigForCert set in its options")
}
return newWithCache(certCache, cfg)
}
// newWithCache ensures that cfg is a valid config by populating
// zero-value fields from the Default Config. If certCache is
// nil, this function panics.
func newWithCache(certCache *Cache, cfg Config) *Config {
if certCache == nil {
panic("cannot make a valid config without a pointer to a certificate cache")
}
// fill in default values
if cfg.CA == "" {
cfg.CA = CA
cfg.CA = Default.CA
}
if cfg.Email == "" {
cfg.Email = Email
cfg.Email = Default.Email
}
if cfg.OnDemand == nil {
cfg.OnDemand = OnDemand
cfg.OnDemand = Default.OnDemand
}
if !cfg.Agreed {
cfg.Agreed = Agreed
cfg.Agreed = Default.Agreed
}
if !cfg.DisableHTTPChallenge {
cfg.DisableHTTPChallenge = DisableHTTPChallenge
cfg.DisableHTTPChallenge = Default.DisableHTTPChallenge
}
if !cfg.DisableTLSALPNChallenge {
cfg.DisableTLSALPNChallenge = DisableTLSALPNChallenge
cfg.DisableTLSALPNChallenge = Default.DisableTLSALPNChallenge
}
if cfg.RenewDurationBefore == 0 {
cfg.RenewDurationBefore = RenewDurationBefore
cfg.RenewDurationBefore = Default.RenewDurationBefore
}
if cfg.RenewDurationBeforeAtStartup == 0 {
cfg.RenewDurationBeforeAtStartup = RenewDurationBeforeAtStartup
cfg.RenewDurationBeforeAtStartup = Default.RenewDurationBeforeAtStartup
}
if cfg.OnEvent == nil {
cfg.OnEvent = OnEvent
cfg.OnEvent = Default.OnEvent
}
if cfg.ListenHost == "" {
cfg.ListenHost = ListenHost
cfg.ListenHost = Default.ListenHost
}
if cfg.AltHTTPPort == 0 {
cfg.AltHTTPPort = AltHTTPPort
cfg.AltHTTPPort = Default.AltHTTPPort
}
if cfg.AltTLSALPNPort == 0 {
cfg.AltTLSALPNPort = AltTLSALPNPort
cfg.AltTLSALPNPort = Default.AltTLSALPNPort
}
if cfg.DNSProvider == nil {
cfg.DNSProvider = DNSProvider
cfg.DNSProvider = Default.DNSProvider
}
if cfg.KeyType == "" {
cfg.KeyType = KeyType
cfg.KeyType = Default.KeyType
}
if cfg.CertObtainTimeout == 0 {
cfg.CertObtainTimeout = CertObtainTimeout
cfg.CertObtainTimeout = Default.CertObtainTimeout
}
if cfg.DefaultServerName == "" {
cfg.DefaultServerName = DefaultServerName
cfg.DefaultServerName = Default.DefaultServerName
}
if cfg.OnDemand == nil {
cfg.OnDemand = OnDemand
cfg.OnDemand = Default.OnDemand
}
if !cfg.MustStaple {
cfg.MustStaple = MustStaple
cfg.MustStaple = Default.MustStaple
}
if cfg.Storage == nil {
cfg.Storage = Default.Storage
}
if cfg.NewManager == nil {
cfg.NewManager = Default.NewManager
}
// absolutely don't allow a nil storage,
// because that would make almost anything
// a config can do pointless
if cfg.Storage == nil {
cfg.Storage = defaultFileStorage
}
// ensure the unexported fields are valid
cfg.certificates = make(map[string]string)
cfg.certCache = certCache
cfg.acmeClients = make(map[string]*lego.Client)
cfg.acmeClientsMu = new(sync.Mutex)
@@ -272,7 +322,7 @@ func (cfg *Config) Manage(domainNames []string) error {
}
// for existing certificates, make sure it is renewed
if cert.NeedsRenewal() {
if cert.NeedsRenewal(cfg) {
err := cfg.RenewCert(domainName, false)
if err != nil {
return fmt.Errorf("%s: renewing certificate: %v", domainName, err)
@@ -303,11 +353,11 @@ func (cfg *Config) ObtainCert(name string, interactive bool) error {
if skip {
return nil
}
client, err := cfg.newACMEClient(interactive)
manager, err := cfg.newManager(interactive)
if err != nil {
return err
}
return client.Obtain(name)
return manager.Obtain(name)
}
// RenewCert renews the certificate for name using cfg. It stows the
@@ -320,20 +370,20 @@ func (cfg *Config) RenewCert(name string, interactive bool) error {
if skip {
return nil
}
client, err := cfg.newACMEClient(interactive)
manager, err := cfg.newManager(interactive)
if err != nil {
return err
}
return client.Renew(name)
return manager.Renew(name)
}
// RevokeCert revokes the certificate for domain via ACME protocol.
func (cfg *Config) RevokeCert(domain string, interactive bool) error {
client, err := cfg.newACMEClient(interactive)
manager, err := cfg.newManager(interactive)
if err != nil {
return err
}
return client.Revoke(domain)
return manager.Revoke(domain)
}
// TLSConfig is an opinionated method that returns a
@@ -394,18 +444,26 @@ func (cfg *Config) storageHasCertResources(domain string) bool {
certKey := StorageKeys.SiteCert(cfg.CA, domain)
keyKey := StorageKeys.SitePrivateKey(cfg.CA, domain)
metaKey := StorageKeys.SiteMeta(cfg.CA, domain)
return cfg.certCache.storage.Exists(certKey) &&
cfg.certCache.storage.Exists(keyKey) &&
cfg.certCache.storage.Exists(metaKey)
return cfg.Storage.Exists(certKey) &&
cfg.Storage.Exists(keyKey) &&
cfg.Storage.Exists(metaKey)
}
// managedCertNeedsRenewal returns true if certRes is
// expiring soon or already expired, or if the process
// of checking the expiration returned an error.
func (cfg *Config) managedCertNeedsRenewal(certRes certificate.Resource) bool {
cert, err := cfg.makeCertificate(certRes.Certificate, certRes.PrivateKey)
cert, err := makeCertificate(certRes.Certificate, certRes.PrivateKey)
if err != nil {
return true
}
return cert.NeedsRenewal()
return cert.NeedsRenewal(cfg)
}
// Manager is a type that can manage a certificate.
// They are usually very short-lived.
type Manager interface {
Obtain(name string) error
Renew(name string) error
Revoke(name string) error
}