From c13ddbd68cbfd4da574e7275e0bfae5230aa1dd0 Mon Sep 17 00:00:00 2001 From: Lz Date: Sun, 5 Jan 2025 11:29:30 +0800 Subject: [PATCH] refactor(autossl): redesign autossl feature --- ext/autossl/autossl.go | 59 ++++++++++++++++++++------------- ext/autossl/autossl_test.go | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 ext/autossl/autossl_test.go diff --git a/ext/autossl/autossl.go b/ext/autossl/autossl.go index b2f9132..018ff13 100644 --- a/ext/autossl/autossl.go +++ b/ext/autossl/autossl.go @@ -3,52 +3,65 @@ package autossl import ( "crypto/tls" "net/http" - "time" "golang.org/x/crypto/acme/autocert" ) -// New creates and returns two HTTP servers: one for HTTP and one for HTTPS. -// The HTTP server redirects all traffic to HTTPS using the autocert.Manager's HTTPHandler. -// The HTTPS server uses the provided ServeMux and autocert.Manager for automatic TLS certificate management. +// AutoSSL is a wrapper around autocert.Manager that provides automatic +// management of SSL/TLS certificates. It embeds autocert.Manager to +// inherit its methods and functionalities, allowing for seamless +// integration and usage of automatic certificate management in your +// application. +type AutoSSL struct { + *autocert.Manager +} + +// New creates a new AutoSSL instance with the provided options. +// It initializes an autocert.Manager with the AcceptTOS prompt. +// If no cache is provided in the options, it defaults to using a directory cache. // // Parameters: // -// mux - The HTTP request multiplexer to use for the HTTPS server. // opts - A variadic list of Option functions to configure the autocert.Manager. // // Returns: // -// *http.Server - The HTTP server configured to redirect traffic to HTTPS. -// *http.Server - The HTTPS server configured with automatic TLS certificate management. -func New(mux *http.ServeMux, opts ...Option) (*http.Server, *http.Server) { - cm := autocert.Manager{ +// A pointer to an AutoSSL instance with the configured autocert.Manager. +func New(opts ...Option) *AutoSSL { + cm := &autocert.Manager{ Prompt: autocert.AcceptTOS, } for _, opt := range opts { - opt(&cm) + opt(cm) } if cm.Cache == nil { cm.Cache = autocert.DirCache(".") } - httpServer := &http.Server{ - Addr: ":http", - Handler: cm.HTTPHandler(mux), - ReadHeaderTimeout: 3 * time.Second, + return &AutoSSL{ + Manager: cm, } +} + +// Configure sets up the HTTP and HTTPS servers with the necessary handlers and TLS configurations. +// It modifies the HTTP server to use the AutoSSL manager's HTTP handler and ensures the HTTPS server +// has a TLS configuration with at least TLS 1.2. It also sets the GetCertificate function for the +// HTTPS server's TLS configuration to use the AutoSSL manager's GetCertificate method. +// +// Parameters: +// - httpSrv: A pointer to the HTTP server to be configured. +// - httpsSrv: A pointer to the HTTPS server to be configured. +func (autossl *AutoSSL) Configure(httpSrv *http.Server, httpsSrv *http.Server) { + httpSrv.Handler = autossl.Manager.HTTPHandler(httpSrv.Handler) - httpsServer := &http.Server{ - Addr: ":https", - Handler: mux, - TLSConfig: &tls.Config{ - MinVersion: tls.VersionTLS12, - MaxVersion: 0, - GetCertificate: cm.GetCertificate, - }, + if httpsSrv.TLSConfig == nil { + httpsSrv.TLSConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: 0, + } } - return httpServer, httpsServer + httpsSrv.TLSConfig.GetCertificate = autossl.Manager.GetCertificate } diff --git a/ext/autossl/autossl_test.go b/ext/autossl/autossl_test.go new file mode 100644 index 0000000..c0e1c32 --- /dev/null +++ b/ext/autossl/autossl_test.go @@ -0,0 +1,65 @@ +package autossl + +import ( + "context" + "crypto/tls" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/acme/autocert" +) + +func TestNew(t *testing.T) { + as := New() + + require.NotNil(t, as) + require.NotNil(t, as.Manager) + require.True(t, as.Prompt("")) + require.NotNil(t, as.Manager.Cache) +} + +func TestConfigure(t *testing.T) { + as := New() + require.NotNil(t, as) + + httpSrv := &http.Server{} + httpsSrv := &http.Server{} + + as.Configure(httpSrv, httpsSrv) + + require.NotNil(t, httpSrv.Handler) + require.NotNil(t, httpsSrv.TLSConfig) + + require.Equal(t, uint16(tls.VersionTLS12), httpsSrv.TLSConfig.MinVersion) + require.Equal(t, uint16(0), httpsSrv.TLSConfig.MaxVersion) + + require.NotNil(t, httpsSrv.TLSConfig.GetCertificate) + + httpSrv = &http.Server{} + httpsSrv = &http.Server{ + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS10, + MaxVersion: tls.VersionTLS13, + }, + } + + as.Configure(httpSrv, httpsSrv) + require.NotNil(t, httpSrv.Handler) + require.NotNil(t, httpsSrv.TLSConfig) + + require.Equal(t, uint16(tls.VersionTLS10), httpsSrv.TLSConfig.MinVersion) + require.Equal(t, uint16(tls.VersionTLS13), httpsSrv.TLSConfig.MaxVersion) + + require.NotNil(t, httpsSrv.TLSConfig.GetCertificate) +} + +func TestOptions(t *testing.T) { + as := New(WithCache(autocert.DirCache(".")), WithHosts("abc.com")) + + require.NotNil(t, as) + require.IsType(t, autocert.DirCache("."), as.Manager.Cache) + require.Nil(t, as.Manager.HostPolicy(context.TODO(), "abc.com")) + require.NotNil(t, as.Manager.HostPolicy(context.TODO(), "123.com")) + +}