Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
General cleanup and more godocs
Matthew Holt committed
Apr 26, 2019 at 12:35 UTC
43961b542b077f99f78d64629348b9300d3cd4a3
5 files changed
+129
-86
modules.go
+34
-5
@@ -11,15 +11,44 @@ import (
11
12
// Module represents a Caddy module.
13
type Module struct {
14
- Name string
15
- New func() (interface{}, error)
16
- OnLoad func(instances []interface{}, priorState interface{}) (newState interface{}, err error)
14
+ // Name is the full name of the module. It
15
+ // must be unique and properly namespaced.
16
+ Name string
17
+
18
+ // New returns a new, empty instance of
19
+ // the module's type. The host module
20
+ // which loads this module will likely
21
+ // invoke methods on the returned value.
22
+ // It must return a pointer; if not, it
23
+ // is converted into one.
24
+ New func() (interface{}, error)
25
+
26
+ // OnLoad is invoked after all module
27
+ // instances ave been loaded. It receives
28
+ // pointers to each instance of this
29
+ // module, and any state from a previous
30
+ // running configuration, which may be
31
+ // nil.
32
+ //
33
+ // If this module is to carry "global"
34
+ // state between all instances through
35
+ // reloads, you might find it helpful
36
+ // to return it.
37
+ // TODO: Is this really better/safer than a global variable?
38
+ OnLoad func(instances []interface{}, priorState interface{}) (newState interface{}, err error)
39
+
40
+ // OnUnload is called after all module
41
+ // instances have been stopped, possibly
42
+ // in favor of a new configuration. It
43
+ // receives the state given by OnLoad (if
44
+ // any).
45
OnUnload func(state interface{}) error
46
}
47
48
func (m Module) String() string { return m.Name }
49
22
-// RegisterModule registers a module.
50
+// RegisterModule registers a module. Modules must call
51
+// this function in the init phase of runtime.
52
func RegisterModule(mod Module) error {
53
if mod.Name == "caddy" {
54
return fmt.Errorf("modules cannot be named 'caddy'")
@@ -35,7 +64,7 @@ func RegisterModule(mod Module) error {
64
return nil
65
}
66
38
-// GetModule returns a module by name.
67
+// GetModule returns a module by its full name.
68
func GetModule(name string) (Module, error) {
69
modulesMu.Lock()
70
defer modulesMu.Unlock()
modules/caddytls/acmemanager.go
+66
-15
@@ -3,6 +3,7 @@ package caddytls
3
import (
4
"encoding/json"
5
"fmt"
6
+ "time"
7
8
"github.com/go-acme/lego/certcrypto"
9
@@ -18,11 +19,6 @@ func init() {
19
})
20
}
21
21
-// ManagerMaker TODO: WIP...
22
-type ManagerMaker interface {
23
- newManager(interactive bool) (certmagic.Manager, error)
24
-}
25
-
22
// acmeManagerMaker makes an ACME manager
23
// for managinig certificates using ACME.
24
type acmeManagerMaker struct {
@@ -40,9 +36,11 @@ type acmeManagerMaker struct {
36
keyType certcrypto.KeyType
37
}
38
43
-func (m *acmeManagerMaker) Provision() error {
44
- m.setDefaults()
39
+func (m *acmeManagerMaker) newManager(interactive bool) (certmagic.Manager, error) {
40
+ return nil, nil
41
+}
42
43
+func (m *acmeManagerMaker) Provision() error {
44
// DNS providers
45
if m.Challenges.DNS != nil {
46
val, err := caddy2.LoadModuleInline("provider", "tls.dns", m.Challenges.DNS)
@@ -67,18 +65,71 @@ func (m *acmeManagerMaker) Provision() error {
65
m.Storage = nil // allow GC to deallocate - TODO: Does this help?
66
}
67
68
+ m.setDefaults()
69
+
70
return nil
71
}
72
73
-// setDefaults indiscriminately sets all the default values in m.
73
+// setDefaults sets necessary values that are
74
+// currently empty to their default values.
75
func (m *acmeManagerMaker) setDefaults() {
75
- m.CA = certmagic.LetsEncryptStagingCA // certmagic.Default.CA // TODO: When not testing, switch to production CA
76
- m.Email = certmagic.Default.Email
77
- m.RenewAhead = caddy2.Duration(certmagic.Default.RenewDurationBefore)
78
- m.keyType = certmagic.Default.KeyType
79
- m.storage = certmagic.Default.Storage
76
+ if m.CA == "" {
77
+ m.CA = certmagic.LetsEncryptStagingCA // certmagic.Default.CA // TODO: When not testing, switch to production CA
78
+ }
79
+ if m.Email == "" {
80
+ m.Email = certmagic.Default.Email
81
+ }
82
+ if m.RenewAhead == 0 {
83
+ m.RenewAhead = caddy2.Duration(certmagic.Default.RenewDurationBefore)
84
+ }
85
+ if m.keyType == "" {
86
+ m.keyType = certmagic.Default.KeyType
87
+ }
88
+ if m.storage == nil {
89
+ m.storage = certmagic.Default.Storage
90
+ }
91
}
92
82
-func (m *acmeManagerMaker) newManager(interactive bool) (certmagic.Manager, error) {
83
- return nil, nil
93
+// makeCertMagicConfig converts m into a certmagic.Config, because
94
+// this is a special case where the default manager is the certmagic
95
+// Config and not a separate manager.
96
+func (m *acmeManagerMaker) makeCertMagicConfig() certmagic.Config {
97
+ storage := m.storage
98
+ if storage == nil {
99
+ storage = caddy2.GetStorage()
100
+ }
101
+
102
+ var ond *certmagic.OnDemandConfig
103
+ if m.OnDemand != nil {
104
+ ond = &certmagic.OnDemandConfig{
105
+ // TODO: fill this out
106
+ }
107
+ }
108
+
109
+ return certmagic.Config{
110
+ CA: certmagic.LetsEncryptStagingCA, //ap.CA, // TODO: Restore true value
111
+ Email: m.Email,
112
+ Agreed: true,
113
+ DisableHTTPChallenge: m.Challenges.HTTP.Disabled,
114
+ DisableTLSALPNChallenge: m.Challenges.TLSALPN.Disabled,
115
+ RenewDurationBefore: time.Duration(m.RenewAhead),
116
+ AltHTTPPort: m.Challenges.HTTP.AlternatePort,
117
+ AltTLSALPNPort: m.Challenges.TLSALPN.AlternatePort,
118
+ DNSProvider: m.Challenges.dns,
119
+ KeyType: supportedCertKeyTypes[m.KeyType],
120
+ CertObtainTimeout: time.Duration(m.ACMETimeout),
121
+ OnDemand: ond,
122
+ MustStaple: m.MustStaple,
123
+ Storage: storage,
124
+ // TODO: listenHost
125
+ }
126
+}
127
+
128
+// supportedCertKeyTypes is all the key types that are supported
129
+// for certificates that are obtained through ACME.
130
+var supportedCertKeyTypes = map[string]certcrypto.KeyType{
131
+ "RSA2048": certcrypto.RSA2048,
132
+ "RSA4096": certcrypto.RSA4096,
133
+ "P256": certcrypto.EC256,
134
+ "P384": certcrypto.EC384,
135
}
modules/caddytls/matchers.go
+17
-3
@@ -7,13 +7,22 @@ import (
7
)
8
9
type (
10
+ // MatchServerName matches based on SNI.
11
MatchServerName []string
12
13
// TODO: these others should be enterprise-only, probably
13
- MatchProtocol []string // TODO: version or protocol?
14
+
15
+ // MatchProtocol matches based on protocol.
16
+ MatchProtocol []string // TODO: Protocol or version?
17
+
18
+ // MatchClientCert matches based on client certificate / client auth?
19
MatchClientCert struct{} // TODO: client certificate options
15
- MatchRemote []string
16
- MatchStarlark string
20
+
21
+ // MatchRemote matches based on the remote address of the connection.
22
+ MatchRemote []string
23
+
24
+ // MatchStarlark matches based on a Starlark script.
25
+ MatchStarlark string
26
)
27
28
func init() {
@@ -39,6 +48,7 @@ func init() {
48
})
49
}
50
51
+// Match matches hello based on SNI.
52
func (m MatchServerName) Match(hello *tls.ClientHelloInfo) bool {
53
for _, name := range m {
54
// TODO: support wildcards (and regex?)
@@ -49,21 +59,25 @@ func (m MatchServerName) Match(hello *tls.ClientHelloInfo) bool {
59
return false
60
}
61
62
+// Match matches hello based on protocol version.
63
func (m MatchProtocol) Match(hello *tls.ClientHelloInfo) bool {
64
// TODO: not implemented
65
return false
66
}
67
68
+// Match matches hello based on client certificate.
69
func (m MatchClientCert) Match(hello *tls.ClientHelloInfo) bool {
70
// TODO: not implemented
71
return false
72
}
73
74
+// Match matches hello based on remote address.
75
func (m MatchRemote) Match(hello *tls.ClientHelloInfo) bool {
76
// TODO: not implemented
77
return false
78
}
79
80
+// Match matches hello based on a Starlark script.
81
func (m MatchStarlark) Match(hello *tls.ClientHelloInfo) bool {
82
// TODO: not implemented
83
return false
modules/caddytls/tls.go
+8
-51
@@ -5,10 +5,8 @@ import (
5
"encoding/json"
6
"fmt"
7
"net/http"
8
- "time"
8
9
"bitbucket.org/lightcodelabs/caddy2"
11
- "github.com/go-acme/lego/certcrypto"
10
"github.com/go-acme/lego/challenge"
11
"github.com/klauspost/cpuid"
12
"github.com/mholt/certmagic"
@@ -30,8 +28,7 @@ type TLS struct {
28
certCache *certmagic.Cache
29
}
30
33
-// TODO: Finish stubbing out this two-phase setup process: prepare, then start...
34
-
31
+// Provision sets up the configuration for the TLS app.
32
func (t *TLS) Provision() error {
33
// set up the certificate cache
34
// TODO: this makes a new cache every time; better to only make a new
@@ -97,15 +94,6 @@ func (t *TLS) Start(handle caddy2.Handle) error {
94
if err != nil {
95
return fmt.Errorf("automate: managing %v: %v", names, err)
96
}
100
- // for _, name := range names {
101
- // t.Manage([]string{name)
102
- // ap := t.getAutomationPolicyForName(name)
103
- // magic := certmagic.New(t.certCache, ap.makeCertMagicConfig())
104
- // err := magic.Manage([]string{name})
105
- // if err != nil {
106
- // return fmt.Errorf("automate: manage %s: %v", name, err)
107
- // }
108
- // }
97
}
98
t.Certificates = nil // allow GC to deallocate - TODO: Does this help?
99
@@ -191,38 +179,11 @@ type AutomationPolicy struct {
179
}
180
181
func (ap AutomationPolicy) makeCertMagicConfig() certmagic.Config {
182
+ // default manager (ACME) is a special case because of how CertMagic is designed
183
+ // TODO: refactor certmagic so that ACME manager is not a special case by extracting
184
+ // its config fields out of the certmagic.Config struct, or something...
185
if acmeMgmt, ok := ap.management.(*acmeManagerMaker); ok {
195
- // default, which is management via ACME
196
-
197
- storage := acmeMgmt.storage
198
- if storage == nil {
199
- storage = caddy2.GetStorage()
200
- }
201
-
202
- var ond *certmagic.OnDemandConfig
203
- if acmeMgmt.OnDemand != nil {
204
- ond = &certmagic.OnDemandConfig{
205
- // TODO: fill this out
206
- }
207
- }
208
-
209
- return certmagic.Config{
210
- CA: certmagic.LetsEncryptStagingCA, //ap.CA, // TODO: Restore true value
211
- Email: acmeMgmt.Email,
212
- Agreed: true,
213
- DisableHTTPChallenge: acmeMgmt.Challenges.HTTP.Disabled,
214
- DisableTLSALPNChallenge: acmeMgmt.Challenges.TLSALPN.Disabled,
215
- RenewDurationBefore: time.Duration(acmeMgmt.RenewAhead),
216
- AltHTTPPort: acmeMgmt.Challenges.HTTP.AlternatePort,
217
- AltTLSALPNPort: acmeMgmt.Challenges.TLSALPN.AlternatePort,
218
- DNSProvider: acmeMgmt.Challenges.dns,
219
- KeyType: supportedCertKeyTypes[acmeMgmt.KeyType],
220
- CertObtainTimeout: time.Duration(acmeMgmt.ACMETimeout),
221
- OnDemand: ond,
222
- MustStaple: acmeMgmt.MustStaple,
223
- Storage: storage,
224
- // TODO: listenHost
225
- }
186
+ return acmeMgmt.makeCertMagicConfig()
187
}
188
189
return certmagic.Config{
@@ -260,13 +221,9 @@ type OnDemandConfig struct {
221
AskStarlark string `json:"ask_starlark,omitempty"`
222
}
223
263
-// supportedCertKeyTypes is all the key types that are supported
264
-// for certificates that are obtained through ACME.
265
-var supportedCertKeyTypes = map[string]certcrypto.KeyType{
266
- "RSA2048": certcrypto.RSA2048,
267
- "RSA4096": certcrypto.RSA4096,
268
- "P256": certcrypto.EC256,
269
- "P384": certcrypto.EC384,
224
+// ManagerMaker makes a certificate manager.
225
+type ManagerMaker interface {
226
+ newManager(interactive bool) (certmagic.Manager, error)
227
}
228
229
// supportedCipherSuites is the unordered map of cipher suite
storage.go
+4
-12
@@ -16,22 +16,14 @@ func init() {
16
}
17
18
// StorageConverter is a type that can convert itself
19
-// to a valid, usable certmagic.Storage value. The
20
-// value might be short-lived.
19
+// to a valid, usable certmagic.Storage value. (The
20
+// value might be short-lived.) This interface allows
21
+// us to adapt any CertMagic storage implementation
22
+// into a consistent API for Caddy configuration.
23
type StorageConverter interface {
24
CertMagicStorage() (certmagic.Storage, error)
25
}
26
25
-// TODO: Wrappers other than file_system should be enterprise-only.
26
-
27
-// It may seem trivial to wrap these, but the benefits are:
28
-// 1. We don't need to change the actual CertMagic storage implementions
29
-// to a structure that is operable with Caddy's config (including JSON
30
-// tags), and
31
-// 2. We don't need to rely on rely on maintainers of third-party
32
-// certmagic.Storage implementations. We can make any certmagic.Storage
33
-// work with Caddy this way.
34
-
27
// fileStorage is a certmagic.Storage wrapper for certmagic.FileStorage.
28
type fileStorage struct {
29
Root string `json:"root"`