mirror of
https://github.com/datarhei/core.git
synced 2025-10-05 07:57:13 +08:00
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package autocert
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/datarhei/core/v16/log"
|
|
|
|
"github.com/caddyserver/certmagic"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type Manager interface {
|
|
AcquireCertificates(ctx context.Context, listenAddress string, hostnames []string) error
|
|
GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
|
HTTPChallengeHandler(h http.Handler) http.Handler
|
|
}
|
|
|
|
type Config struct {
|
|
Storage certmagic.Storage
|
|
DefaultHostname string
|
|
EmailAddress string
|
|
IsProduction bool
|
|
Logger log.Logger
|
|
}
|
|
|
|
type manager struct {
|
|
config *certmagic.Config
|
|
|
|
logger log.Logger
|
|
}
|
|
|
|
func New(config Config) (Manager, error) {
|
|
m := &manager{
|
|
logger: config.Logger,
|
|
}
|
|
|
|
if m.logger == nil {
|
|
m.logger = log.New("")
|
|
}
|
|
|
|
certmagic.Default.Storage = config.Storage
|
|
certmagic.Default.DefaultServerName = config.DefaultHostname
|
|
certmagic.Default.Logger = zap.NewNop()
|
|
|
|
ca := certmagic.LetsEncryptStagingCA
|
|
if config.IsProduction {
|
|
ca = certmagic.LetsEncryptProductionCA
|
|
}
|
|
|
|
certmagic.DefaultACME.Agreed = true
|
|
certmagic.DefaultACME.Email = config.EmailAddress
|
|
certmagic.DefaultACME.CA = ca
|
|
certmagic.DefaultACME.DisableHTTPChallenge = false
|
|
certmagic.DefaultACME.DisableTLSALPNChallenge = true
|
|
certmagic.DefaultACME.Logger = zap.NewNop()
|
|
|
|
magic := certmagic.NewDefault()
|
|
acme := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME)
|
|
acme.Logger = zap.NewNop()
|
|
|
|
magic.Issuers = []certmagic.Issuer{acme}
|
|
magic.Logger = zap.NewNop()
|
|
|
|
m.config = magic
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func (m *manager) HTTPChallengeHandler(h http.Handler) http.Handler {
|
|
acme := m.config.Issuers[0].(*certmagic.ACMEIssuer)
|
|
return acme.HTTPChallengeHandler(h)
|
|
}
|
|
|
|
func (m *manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
return m.config.GetCertificate(hello)
|
|
}
|
|
|
|
func (m *manager) AcquireCertificates(ctx context.Context, listenAddress string, hostnames []string) error {
|
|
acme := m.config.Issuers[0].(*certmagic.ACMEIssuer)
|
|
|
|
// Start temporary http server on configured port
|
|
tempserver := &http.Server{
|
|
Addr: listenAddress,
|
|
Handler: acme.HTTPChallengeHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
})),
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
MaxHeaderBytes: 1 << 20,
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
tempserver.ListenAndServe()
|
|
wg.Done()
|
|
}()
|
|
|
|
var certerr error
|
|
|
|
// Get the certificates
|
|
logger := m.logger.WithField("hostnames", hostnames)
|
|
logger.Info().Log("Acquiring certificate ...")
|
|
|
|
err := m.config.ManageSync(ctx, hostnames)
|
|
|
|
if err != nil {
|
|
certerr = fmt.Errorf("failed to acquire certificate for %s: %w", strings.Join(hostnames, ","), err)
|
|
} else {
|
|
logger.Info().Log("Successfully acquired certificate")
|
|
}
|
|
|
|
// Shut down the temporary http server
|
|
tempserver.Close()
|
|
|
|
wg.Wait()
|
|
|
|
return certerr
|
|
}
|