From f35c4d0f667cb2304f1dabf020c7e3f46664dae8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 3 Dec 2021 04:32:30 +0100 Subject: [PATCH] make mem cache an interface and inject --- cmd/main.go | 7 ++++--- server/cache/interface.go | 1 + server/certificates.go | 33 ++++++++++++++++++--------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index ff778d1..98b65d2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -95,15 +95,16 @@ func Serve(ctx *cli.Context) error { defer keyDatabase.Sync() // database has no close ... sync behave like it keyCache := cache.NewKeyValueCache() - listener = tls.NewListener(listener, server.TLSConfig(mainDomainSuffix, giteaRoot, giteaAPIToken, dnsProvider, acmeUseRateLimits, keyCache, keyDatabase)) + challengeCache := cache.NewKeyValueCache() + listener = tls.NewListener(listener, server.TLSConfig(mainDomainSuffix, giteaRoot, giteaAPIToken, dnsProvider, acmeUseRateLimits, keyCache, challengeCache, keyDatabase)) - server.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer, keyDatabase) + server.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer, challengeCache, keyDatabase) if enableHTTPServer { go (func() { challengePath := []byte("/.well-known/acme-challenge/") err := fasthttp.ListenAndServe("[::]:80", func(ctx *fasthttp.RequestCtx) { if bytes.HasPrefix(ctx.Path(), challengePath) { - challenge, ok := server.ChallengeCache.Get(string(utils.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath))) + challenge, ok := challengeCache.Get(string(utils.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath))) if !ok || challenge == nil { ctx.SetStatusCode(http.StatusNotFound) ctx.SetBodyString("no challenge for this token") diff --git a/server/cache/interface.go b/server/cache/interface.go index 37ae8f5..2952b29 100644 --- a/server/cache/interface.go +++ b/server/cache/interface.go @@ -5,4 +5,5 @@ import "time" type SetGetKey interface { Set(key string, value interface{}, ttl time.Duration) error Get(key string) (interface{}, bool) + Remove(key string) } diff --git a/server/certificates.go b/server/certificates.go index d6b6b86..12d42a1 100644 --- a/server/certificates.go +++ b/server/certificates.go @@ -23,7 +23,6 @@ import ( "sync" "time" - "github.com/OrlovEvgeny/go-mcache" "github.com/reugn/equalizer" "github.com/go-acme/lego/v4/certcrypto" @@ -39,7 +38,7 @@ import ( ) // TLSConfig returns the configuration for generating, serving and cleaning up Let's Encrypt certificates. -func TLSConfig(mainDomainSuffix []byte, giteaRoot, giteaApiToken, dnsProvider string, acmeUseRateLimits bool, keyCache cache.SetGetKey, keyDatabase database.KeyDB) *tls.Config { +func TLSConfig(mainDomainSuffix []byte, giteaRoot, giteaApiToken, dnsProvider string, acmeUseRateLimits bool, keyCache, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) *tls.Config { return &tls.Config{ // check DNS name & get certificate from Let's Encrypt GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { @@ -52,7 +51,7 @@ func TLSConfig(mainDomainSuffix []byte, giteaRoot, giteaApiToken, dnsProvider st if info.SupportedProtos != nil { for _, proto := range info.SupportedProtos { if proto == tlsalpn01.ACMETLS1Protocol { - challenge, ok := ChallengeCache.Get(sni) + challenge, ok := challengeCache.Get(sni) if !ok { return nil, errors.New("no challenge for this domain") } @@ -176,29 +175,33 @@ var acmeClientOrderLimit = equalizer.NewTokenBucket(25, 15*time.Minute) // rate limit is 20 / second, we want 5 / second (especially as one cert takes at least two requests) var acmeClientRequestLimit = equalizer.NewTokenBucket(5, 1*time.Second) -var ChallengeCache = mcache.New() - -type AcmeTLSChallengeProvider struct{} +type AcmeTLSChallengeProvider struct { + challengeCache cache.SetGetKey +} +// make sure AcmeTLSChallengeProvider match Provider interface var _ challenge.Provider = AcmeTLSChallengeProvider{} func (a AcmeTLSChallengeProvider) Present(domain, _, keyAuth string) error { - return ChallengeCache.Set(domain, keyAuth, 1*time.Hour) + return a.challengeCache.Set(domain, keyAuth, 1*time.Hour) } func (a AcmeTLSChallengeProvider) CleanUp(domain, _, _ string) error { - ChallengeCache.Remove(domain) + a.challengeCache.Remove(domain) return nil } -type AcmeHTTPChallengeProvider struct{} +type AcmeHTTPChallengeProvider struct { + challengeCache cache.SetGetKey +} +// make sure AcmeHTTPChallengeProvider match Provider interface var _ challenge.Provider = AcmeHTTPChallengeProvider{} func (a AcmeHTTPChallengeProvider) Present(domain, token, keyAuth string) error { - return ChallengeCache.Set(domain+"/"+token, keyAuth, 1*time.Hour) + return a.challengeCache.Set(domain+"/"+token, keyAuth, 1*time.Hour) } func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error { - ChallengeCache.Remove(domain + "/" + token) + a.challengeCache.Remove(domain + "/" + token) return nil } @@ -392,7 +395,7 @@ func mockCert(domain, msg, mainDomainSuffix string, keyDatabase database.KeyDB) return tlsCertificate } -func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider string, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer bool, keyDatabase database.KeyDB) { +func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider string, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) { // getting main cert before ACME account so that we can panic here on database failure without hitting rate limits mainCertBytes, err := keyDatabase.Get(mainDomainSuffix) if err != nil { @@ -475,12 +478,12 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, if err != nil { log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err) } else { - err = acmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{}) + err = acmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache}) if err != nil { log.Printf("[ERROR] Can't create TLS-ALPN-01 provider: %s", err) } if enableHTTPServer { - err = acmeClient.Challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{}) + err = acmeClient.Challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{challengeCache}) if err != nil { log.Printf("[ERROR] Can't create HTTP-01 provider: %s", err) } @@ -493,7 +496,7 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, } else { if dnsProvider == "" { // using mock server, don't use wildcard certs - err := mainDomainAcmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{}) + err := mainDomainAcmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache}) if err != nil { log.Printf("[ERROR] Can't create TLS-ALPN-01 provider: %s", err) }