Skip to content

Commit

Permalink
refactor(autossl): redesign autossl feature
Browse files Browse the repository at this point in the history
  • Loading branch information
cnlangzi committed Jan 5, 2025
1 parent e377653 commit c13ddbd
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
59 changes: 36 additions & 23 deletions ext/autossl/autossl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
65 changes: 65 additions & 0 deletions ext/autossl/autossl_test.go
Original file line number Diff line number Diff line change
@@ -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"))

}

0 comments on commit c13ddbd

Please sign in to comment.