1package acme23import (4 "context"5 "crypto/tls"6 "fmt"7 "path/filepath"89 "github.com/caddyserver/certmagic"10 "github.com/foxcpp/maddy/framework/config"11 modconfig "github.com/foxcpp/maddy/framework/config/module"12 "github.com/foxcpp/maddy/framework/hooks"13 "github.com/foxcpp/maddy/framework/log"14 "github.com/foxcpp/maddy/framework/module"15)1617const modName = "tls.loader.acme"1819type Loader struct {20 instName string2122 store certmagic.Storage23 cache *certmagic.Cache24 cfg *certmagic.Config25 cancelManage context.CancelFunc2627 log log.Logger28}2930func New(_, instName string, _, inlineArgs []string) (module.Module, error) {31 if len(inlineArgs) != 0 {32 return nil, fmt.Errorf("%s: no inline args expected", modName)33 }34 return &Loader{35 instName: instName,36 log: log.Logger{Name: modName},37 }, nil38}3940func (l *Loader) Init(cfg *config.Map) error {41 var (42 hostname string43 extraNames []string44 storePath string45 caPath string46 testCAPath string47 email string48 agreed bool49 challenge string50 overrideDomain string51 provider certmagic.DNSProvider52 )53 cfg.Bool("debug", true, false, &l.log.Debug)54 cfg.String("hostname", true, true, "", &hostname)55 cfg.StringList("extra_names", false, false, nil, &extraNames)56 cfg.String("store_path", false, false,57 filepath.Join(config.StateDirectory, "acme"), &storePath)58 cfg.String("ca", false, false,59 certmagic.LetsEncryptProductionCA, &caPath)60 cfg.String("test_ca", false, false,61 certmagic.LetsEncryptStagingCA, &testCAPath)62 cfg.String("email", false, false,63 "", &email)64 cfg.String("override_domain", false, false,65 "", &overrideDomain)66 cfg.Bool("agreed", false, false, &agreed)67 cfg.Enum("challenge", false, true,68 []string{"dns-01"}, "dns-01", &challenge)69 cfg.Custom("dns", false, false, func() (interface{}, error) {70 return nil, nil71 }, func(m *config.Map, node config.Node) (interface{}, error) {72 var p certmagic.DNSProvider73 err := modconfig.ModuleFromNode("libdns", node.Args, node, m.Globals, &p)74 return p, err75 }, &provider)76 if _, err := cfg.Process(); err != nil {77 return err78 }7980 cmLog := l.log.Zap()8182 l.store = &certmagic.FileStorage{Path: storePath}83 l.cache = certmagic.NewCache(certmagic.CacheOptions{84 Logger: cmLog,85 GetConfigForCert: func(c certmagic.Certificate) (*certmagic.Config, error) {86 return l.cfg, nil87 },88 })8990 l.cfg = certmagic.New(l.cache, certmagic.Config{91 Storage: l.store, // not sure if it is necessary to set these twice92 Logger: cmLog,93 DefaultServerName: hostname,94 })95 issuer := certmagic.NewACMEIssuer(l.cfg, certmagic.ACMEIssuer{96 Logger: cmLog,97 CA: caPath,98 TestCA: testCAPath,99 Email: email,100 Agreed: agreed,101 })102103 switch challenge {104 case "dns-01":105 issuer.DisableTLSALPNChallenge = true106 issuer.DisableHTTPChallenge = true107 if provider == nil {108 return fmt.Errorf("tls.loader.acme: dns-01 challenge requires a configured DNS provider")109 }110 issuer.DNS01Solver = &certmagic.DNS01Solver{111 DNSManager: certmagic.DNSManager{112 DNSProvider: provider,113 OverrideDomain: overrideDomain,114 },115 }116 default:117 return fmt.Errorf("tls.loader.acme: challenge not supported")118 }119 l.cfg.Issuers = []certmagic.Issuer{issuer}120121 if module.NoRun {122 return nil123 }124125 manageCtx, cancelManage := context.WithCancel(context.Background())126 err := l.cfg.ManageAsync(manageCtx, append([]string{hostname}, extraNames...))127 if err != nil {128 cancelManage()129 return err130 }131 l.cancelManage = cancelManage132133 return nil134}135136func (l *Loader) ConfigureTLS(c *tls.Config) error {137 c.GetCertificate = l.cfg.GetCertificate138 return nil139}140141func (l *Loader) Close() error {142 l.cancelManage()143 l.cache.Stop()144 return nil145}146147func (l *Loader) Name() string {148 return modName149}150151func (l *Loader) InstanceName() string {152 return l.instName153}154155func init() {156 hooks.AddHook(hooks.EventShutdown, func() {157 certmagic.CleanUpOwnLocks(context.TODO(), log.DefaultLogger.Zap())158 })159}160161func init() {162 var _ module.TLSLoader = &Loader{}163 module.Register(modName, New)164}