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
Refactor for CertMagic v0.10; prepare for PKI app
This is a breaking change primarily in two areas: - Storage paths for certificates have changed - Slight changes to JSON config parameters Huge improvements in this commit, to be detailed more in the release notes. The upcoming PKI app will be powered by Smallstep libraries.
Matthew Holt committed
Mar 6, 2020 at 23:15 UTC
b8cba62643abf849411856bd92c42b59b98779f4
36 files changed
+1942
-616
README.md
+1
-1
@@ -44,7 +44,7 @@ This is the development branch for Caddy 2.
44
<p align="center">
45
<b>Powered by</b>
46
<br>
47
- <a href="https://github.com/mholt/certmagic"><img src="https://user-images.githubusercontent.com/1128849/49704830-49d37200-fbd5-11e8-8385-767e0cd033c3.png" alt="CertMagic" width="250"></a>
47
+ <a href="https://github.com/caddyserver/certmagic"><img src="https://user-images.githubusercontent.com/1128849/49704830-49d37200-fbd5-11e8-8385-767e0cd033c3.png" alt="CertMagic" width="250"></a>
48
</p>
49
50
## Build from source
caddy.go
+6
-8
@@ -32,7 +32,7 @@ import (
32
"sync"
33
"time"
34
35
- "github.com/mholt/certmagic"
35
+ "github.com/caddyserver/certmagic"
36
"go.uber.org/zap"
37
)
38
@@ -382,14 +382,12 @@ func run(newCfg *Config, start bool) error {
382
return err
383
}
384
385
- // Load, Provision, Validate each app and their submodules
385
+ // Load and Provision each app and their submodules
386
err = func() error {
387
- appsIface, err := ctx.LoadModule(newCfg, "AppsRaw")
388
- if err != nil {
389
- return fmt.Errorf("loading app modules: %v", err)
390
- }
391
- for appName, appIface := range appsIface.(map[string]interface{}) {
392
- newCfg.apps[appName] = appIface.(App)
387
+ for appName := range newCfg.AppsRaw {
388
+ if _, err := ctx.App(appName); err != nil {
389
+ return err
390
+ }
391
}
392
return nil
393
}()
caddyconfig/httpcaddyfile/addresses.go
+1
-1
@@ -23,7 +23,7 @@ import (
23
24
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
25
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
26
- "github.com/mholt/certmagic"
26
+ "github.com/caddyserver/certmagic"
27
)
28
29
// mapAddressToServerBlocks returns a map of listener address to list of server
caddyconfig/httpcaddyfile/builtins.go
+113
-3
@@ -24,8 +24,10 @@ import (
24
25
"github.com/caddyserver/caddy/v2"
26
"github.com/caddyserver/caddy/v2/caddyconfig"
27
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
28
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
29
"github.com/caddyserver/caddy/v2/modules/caddytls"
30
+ "go.uber.org/zap/zapcore"
31
)
32
33
func init() {
@@ -37,6 +39,7 @@ func init() {
39
RegisterHandlerDirective("route", parseRoute)
40
RegisterHandlerDirective("handle", parseSegmentAsSubroute)
41
RegisterDirective("handle_errors", parseHandleErrors)
42
+ RegisterDirective("log", parseLog)
43
}
44
45
// parseBind parses the bind directive. Syntax:
@@ -108,7 +111,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
111
var cp *caddytls.ConnectionPolicy
112
var fileLoader caddytls.FileLoader
113
var folderLoader caddytls.FolderLoader
111
- var mgr caddytls.ACMEManagerMaker
114
+ var mgr caddytls.ACMEIssuer
115
116
// fill in global defaults, if configured
117
if email := h.Option("email"); email != nil {
@@ -307,9 +310,9 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
310
}
311
312
// automation policy
310
- if !reflect.DeepEqual(mgr, caddytls.ACMEManagerMaker{}) {
313
+ if !reflect.DeepEqual(mgr, caddytls.ACMEIssuer{}) {
314
configVals = append(configVals, ConfigValue{
312
- Class: "tls.automation_manager",
315
+ Class: "tls.cert_issuer",
316
Value: mgr,
317
})
318
}
@@ -426,9 +429,116 @@ func parseHandleErrors(h Helper) ([]ConfigValue, error) {
429
}, nil
430
}
431
432
+// parseLog parses the log directive. Syntax:
433
+//
434
+// log {
435
+// output <writer_module> ...
436
+// format <encoder_module> ...
437
+// level <level>
438
+// }
439
+//
440
+func parseLog(h Helper) ([]ConfigValue, error) {
441
+ var configValues []ConfigValue
442
+ for h.Next() {
443
+ cl := new(caddy.CustomLog)
444
+
445
+ for h.NextBlock(0) {
446
+ switch h.Val() {
447
+ case "output":
448
+ if !h.NextArg() {
449
+ return nil, h.ArgErr()
450
+ }
451
+ moduleName := h.Val()
452
+
453
+ // can't use the usual caddyfile.Unmarshaler flow with the
454
+ // standard writers because they are in the caddy package
455
+ // (because they are the default) and implementing that
456
+ // interface there would unfortunately create circular import
457
+ var wo caddy.WriterOpener
458
+ switch moduleName {
459
+ case "stdout":
460
+ wo = caddy.StdoutWriter{}
461
+ case "stderr":
462
+ wo = caddy.StderrWriter{}
463
+ case "discard":
464
+ wo = caddy.DiscardWriter{}
465
+ default:
466
+ mod, err := caddy.GetModule("caddy.logging.writers." + moduleName)
467
+ if err != nil {
468
+ return nil, h.Errf("getting log writer module named '%s': %v", moduleName, err)
469
+ }
470
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
471
+ if !ok {
472
+ return nil, h.Errf("log writer module '%s' is not a Caddyfile unmarshaler", mod)
473
+ }
474
+ err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
475
+ if err != nil {
476
+ return nil, err
477
+ }
478
+ wo, ok = unm.(caddy.WriterOpener)
479
+ if !ok {
480
+ return nil, h.Errf("module %s is not a WriterOpener", mod)
481
+ }
482
+ }
483
+ cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
484
+
485
+ case "format":
486
+ if !h.NextArg() {
487
+ return nil, h.ArgErr()
488
+ }
489
+ moduleName := h.Val()
490
+ mod, err := caddy.GetModule("caddy.logging.encoders." + moduleName)
491
+ if err != nil {
492
+ return nil, h.Errf("getting log encoder module named '%s': %v", moduleName, err)
493
+ }
494
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
495
+ if !ok {
496
+ return nil, h.Errf("log encoder module '%s' is not a Caddyfile unmarshaler", mod)
497
+ }
498
+ err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
499
+ if err != nil {
500
+ return nil, err
501
+ }
502
+ enc, ok := unm.(zapcore.Encoder)
503
+ if !ok {
504
+ return nil, h.Errf("module %s is not a zapcore.Encoder", mod)
505
+ }
506
+ cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)
507
+
508
+ case "level":
509
+ if !h.NextArg() {
510
+ return nil, h.ArgErr()
511
+ }
512
+ cl.Level = h.Val()
513
+ if h.NextArg() {
514
+ return nil, h.ArgErr()
515
+ }
516
+
517
+ default:
518
+ return nil, h.Errf("unrecognized subdirective: %s", h.Val())
519
+ }
520
+ }
521
+
522
+ var val namedCustomLog
523
+ if !reflect.DeepEqual(cl, new(caddy.CustomLog)) {
524
+ cl.Include = []string{"http.log.access"}
525
+ val.name = fmt.Sprintf("log%d", logCounter)
526
+ val.log = cl
527
+ logCounter++
528
+ }
529
+ configValues = append(configValues, ConfigValue{
530
+ Class: "custom_log",
531
+ Value: val,
532
+ })
533
+ }
534
+ return configValues, nil
535
+}
536
+
537
// tlsCertTags maps certificate filenames to their tag.
538
// This is used to remember which tag is used for each
539
// certificate files, since we need to avoid loading
540
// the same certificate files more than once, overwriting
541
// previous tags
542
var tlsCertTags = make(map[string]string)
543
+
544
+var logCounter int
caddyconfig/httpcaddyfile/directives.go
+31
-4
@@ -17,6 +17,7 @@ package httpcaddyfile
17
import (
18
"encoding/json"
19
"sort"
20
+ "strings"
21
22
"github.com/caddyserver/caddy/v2"
23
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -298,17 +299,43 @@ func sortRoutes(routes []ConfigValue) {
299
// and returned.
300
func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) {
301
var allResults []ConfigValue
302
+
303
for h.Next() {
304
+ // slice the linear list of tokens into top-level segments
305
+ var segments []caddyfile.Segment
306
for nesting := h.Nesting(); h.NextBlock(nesting); {
303
- dir := h.Val()
307
+ segments = append(segments, h.NextSegment())
308
+ }
309
310
+ // copy existing matcher definitions so we can augment
311
+ // new ones that are defined only in this scope
312
+ matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs))
313
+ for key, val := range h.matcherDefs {
314
+ matcherDefs[key] = val
315
+ }
316
+
317
+ // find and extract any embedded matcher definitions in this scope
318
+ for i, seg := range segments {
319
+ if strings.HasPrefix(seg.Directive(), matcherPrefix) {
320
+ err := parseMatcherDefinitions(caddyfile.NewDispenser(seg), matcherDefs)
321
+ if err != nil {
322
+ return nil, err
323
+ }
324
+ segments = append(segments[:i], segments[i+1:]...)
325
+ }
326
+ }
327
+
328
+ // with matchers ready to go, evaluate each directive's segment
329
+ for _, seg := range segments {
330
+ dir := seg.Directive()
331
dirFunc, ok := registeredDirectives[dir]
332
if !ok {
333
return nil, h.Errf("unrecognized directive: %s", dir)
334
}
335
336
subHelper := h
311
- subHelper.Dispenser = h.NewFromNextSegment()
337
+ subHelper.Dispenser = caddyfile.NewDispenser(seg)
338
+ subHelper.matcherDefs = matcherDefs
339
340
results, err := dirFunc(subHelper)
341
if err != nil {
@@ -319,9 +346,9 @@ func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) {
346
allResults = append(allResults, result)
347
}
348
}
322
- return buildSubroute(allResults, h.groupCounter) // TODO: should we move this outside the loop?
349
}
324
- return nil, nil
350
+
351
+ return buildSubroute(allResults, h.groupCounter)
352
}
353
354
// serverBlock pairs a Caddyfile server block
caddyconfig/httpcaddyfile/httptype.go
+108
-10
@@ -26,7 +26,7 @@ import (
26
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
27
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
28
"github.com/caddyserver/caddy/v2/modules/caddytls"
29
- "github.com/mholt/certmagic"
29
+ "github.com/caddyserver/certmagic"
30
)
31
32
func init() {
@@ -88,6 +88,13 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
88
"{remote}", "{http.request.remote}",
89
"{scheme}", "{http.request.scheme}",
90
"{uri}", "{http.request.uri}",
91
+
92
+ "{tls_cipher}", "{http.request.tls.cipher_suite}",
93
+ "{tls_version}", "{http.request.tls.version}",
94
+ "{tls_client_fingerprint}", "{http.request.tls.client.fingerprint}",
95
+ "{tls_client_issuer}", "{http.request.tls.client.issuer}",
96
+ "{tls_client_serial}", "{http.request.tls.client.serial}",
97
+ "{tls_client_subject}", "{http.request.tls.client.subject}",
98
)
99
for _, segment := range sb.block.Segments {
100
for i := 0; i < len(segment); i++ {
@@ -173,9 +180,9 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
180
for _, p := range pairings {
181
for i, sblock := range p.serverBlocks {
182
// tls automation policies
176
- if mmVals, ok := sblock.pile["tls.automation_manager"]; ok {
183
+ if mmVals, ok := sblock.pile["tls.cert_issuer"]; ok {
184
for _, mmVal := range mmVals {
178
- mm := mmVal.Value.(caddytls.ManagerMaker)
185
+ mm := mmVal.Value.(certmagic.Issuer)
186
sblockHosts, err := st.autoHTTPSHosts(sblock)
187
if err != nil {
188
return nil, warnings, err
@@ -185,8 +192,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
192
tlsApp.Automation = new(caddytls.AutomationConfig)
193
}
194
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, &caddytls.AutomationPolicy{
188
- Hosts: sblockHosts,
189
- ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID.Name(), &warnings),
195
+ Hosts: sblockHosts,
196
+ IssuerRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID.Name(), &warnings),
197
})
198
} else {
199
warnings = append(warnings, caddyconfig.Warning{
@@ -245,7 +252,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
252
if !hasEmail {
253
email = ""
254
}
248
- mgr := caddytls.ACMEManagerMaker{
255
+ mgr := caddytls.ACMEIssuer{
256
CA: acmeCA.(string),
257
Email: email.(string),
258
}
@@ -260,7 +267,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
267
}
268
}
269
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, &caddytls.AutomationPolicy{
263
- ManagementRaw: caddyconfig.JSONModuleObject(mgr, "module", "acme", &warnings),
270
+ IssuerRaw: caddyconfig.JSONModuleObject(mgr, "module", "acme", &warnings),
271
})
272
}
273
if tlsApp.Automation != nil {
@@ -275,6 +282,35 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
282
}
283
}
284
285
+ // extract any custom logs, and enforce configured levels
286
+ var customLogs []namedCustomLog
287
+ var hasDefaultLog bool
288
+ for _, sb := range serverBlocks {
289
+ for _, clVal := range sb.pile["custom_log"] {
290
+ ncl := clVal.Value.(namedCustomLog)
291
+ if ncl.name == "" {
292
+ continue
293
+ }
294
+ if ncl.name == "default" {
295
+ hasDefaultLog = true
296
+ }
297
+ if _, ok := options["debug"]; ok && ncl.log.Level == "" {
298
+ ncl.log.Level = "DEBUG"
299
+ }
300
+ customLogs = append(customLogs, ncl)
301
+ }
302
+ }
303
+ if !hasDefaultLog {
304
+ // if the default log was not customized, ensure we
305
+ // configure it with any applicable options
306
+ if _, ok := options["debug"]; ok {
307
+ customLogs = append(customLogs, namedCustomLog{
308
+ name: "default",
309
+ log: &caddy.CustomLog{Level: "DEBUG"},
310
+ })
311
+ }
312
+ }
313
+
314
// annnd the top-level config, then we're done!
315
cfg := &caddy.Config{AppsRaw: make(caddy.ModuleMap)}
316
if !reflect.DeepEqual(httpApp, caddyhttp.App{}) {
@@ -292,6 +328,18 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
328
if adminConfig, ok := options["admin"].(string); ok && adminConfig != "" {
329
cfg.Admin = &caddy.AdminConfig{Listen: adminConfig}
330
}
331
+ if len(customLogs) > 0 {
332
+ if cfg.Logging == nil {
333
+ cfg.Logging = &caddy.Logging{
334
+ Logs: make(map[string]*caddy.CustomLog),
335
+ }
336
+ }
337
+ for _, ncl := range customLogs {
338
+ if ncl.name != "" {
339
+ cfg.Logging.Logs[ncl.name] = ncl.log
340
+ }
341
+ }
342
+ }
343
344
return cfg, warnings, nil
345
}
@@ -316,6 +364,8 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
364
val, err = parseOptHTTPPort(disp)
365
case "https_port":
366
val, err = parseOptHTTPSPort(disp)
367
+ case "default_sni":
368
+ val, err = parseOptSingleString(disp)
369
case "order":
370
val, err = parseOptOrder(disp)
371
case "experimental_http3":
@@ -323,11 +373,13 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
373
case "storage":
374
val, err = parseOptStorage(disp)
375
case "acme_ca", "acme_dns", "acme_ca_root":
326
- val, err = parseOptACME(disp)
376
+ val, err = parseOptSingleString(disp)
377
case "email":
328
- val, err = parseOptEmail(disp)
378
+ val, err = parseOptSingleString(disp)
379
case "admin":
380
val, err = parseOptAdmin(disp)
381
+ case "debug":
382
+ options["debug"] = true
383
default:
384
return nil, fmt.Errorf("unrecognized parameter name: %s", dir)
385
}
@@ -426,6 +478,7 @@ func (st *ServerType) serversFromPairings(
478
}
479
480
// tls: connection policies and toggle auto HTTPS
481
+ defaultSNI := tryString(options["default_sni"], warnings)
482
autoHTTPSQualifiedHosts, err := st.autoHTTPSHosts(sblock)
483
if err != nil {
484
return nil, err
@@ -438,6 +491,7 @@ func (st *ServerType) serversFromPairings(
491
srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, autoHTTPSQualifiedHosts...)
492
} else if cpVals, ok := sblock.pile["tls.connection_policy"]; ok {
493
// tls connection policies
494
+
495
for _, cpVal := range cpVals {
496
cp := cpVal.Value.(*caddytls.ConnectionPolicy)
497
@@ -446,6 +500,13 @@ func (st *ServerType) serversFromPairings(
500
if err != nil {
501
return nil, err
502
}
503
+ for _, h := range hosts {
504
+ if h == defaultSNI {
505
+ hosts = append(hosts, "")
506
+ cp.DefaultSNI = defaultSNI
507
+ break
508
+ }
509
+ }
510
511
// TODO: are matchers needed if every hostname of the resulting config is matched?
512
if len(hosts) > 0 {
@@ -459,6 +520,11 @@ func (st *ServerType) serversFromPairings(
520
srv.TLSConnPolicies = append(srv.TLSConnPolicies, cp)
521
}
522
// TODO: consolidate equal conn policies
523
+ } else if defaultSNI != "" {
524
+ hasCatchAllTLSConnPolicy = true
525
+ srv.TLSConnPolicies = append(srv.TLSConnPolicies, &caddytls.ConnectionPolicy{
526
+ DefaultSNI: defaultSNI,
527
+ })
528
}
529
530
// exclude any hosts that were defined explicitly with
@@ -499,6 +565,25 @@ func (st *ServerType) serversFromPairings(
565
srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, matcherSetsEnc, p, warnings)
566
}
567
}
568
+
569
+ // add log associations
570
+ for _, cval := range sblock.pile["custom_log"] {
571
+ ncl := cval.Value.(namedCustomLog)
572
+ if srv.Logs == nil {
573
+ srv.Logs = &caddyhttp.ServerLogConfig{
574
+ LoggerNames: make(map[string]string),
575
+ }
576
+ }
577
+ hosts, err := st.hostsFromServerBlockKeys(sblock.block)
578
+ if err != nil {
579
+ return nil, err
580
+ }
581
+ for _, h := range hosts {
582
+ if ncl.name != "" {
583
+ srv.Logs.LoggerNames[h] = ncl.name
584
+ }
585
+ }
586
+ }
587
}
588
589
// a catch-all TLS conn policy is necessary to ensure TLS can
@@ -690,7 +775,7 @@ func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls
775
// otherwise the one without any hosts (a catch-all) would be
776
// eaten up by the one with hosts; and if both have hosts, we
777
// need to combine their lists
693
- if reflect.DeepEqual(aps[i].ManagementRaw, aps[j].ManagementRaw) &&
778
+ if reflect.DeepEqual(aps[i].IssuerRaw, aps[j].IssuerRaw) &&
779
aps[i].ManageSync == aps[j].ManageSync {
780
if len(aps[i].Hosts) == 0 && len(aps[j].Hosts) > 0 {
781
aps = append(aps[:j], aps[j+1:]...)
@@ -882,6 +967,14 @@ func tryInt(val interface{}, warnings *[]caddyconfig.Warning) int {
967
return intVal
968
}
969
970
+func tryString(val interface{}, warnings *[]caddyconfig.Warning) string {
971
+ stringVal, ok := val.(string)
972
+ if val != nil && !ok && warnings != nil {
973
+ *warnings = append(*warnings, caddyconfig.Warning{Message: "not a string type"})
974
+ }
975
+ return stringVal
976
+}
977
+
978
// sliceContains returns true if needle is in haystack.
979
func sliceContains(haystack []string, needle string) bool {
980
for _, s := range haystack {
@@ -933,6 +1026,11 @@ type matcherSetAndTokens struct {
1026
tokens []caddyfile.Token
1027
}
1028
1029
+type namedCustomLog struct {
1030
+ name string
1031
+ log *caddy.CustomLog
1032
+}
1033
+
1034
// sbAddrAssocation is a mapping from a list of
1035
// addresses to a list of server blocks that are
1036
// served on those addresses.
caddyconfig/httpcaddyfile/options.go
+1
-15
@@ -162,19 +162,7 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
162
return storage, nil
163
}
164
165
-func parseOptACME(d *caddyfile.Dispenser) (string, error) {
166
- d.Next() // consume parameter name
167
- if !d.Next() {
168
- return "", d.ArgErr()
169
- }
170
- val := d.Val()
171
- if d.Next() {
172
- return "", d.ArgErr()
173
- }
174
- return val, nil
175
-}
176
-
177
-func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
165
+func parseOptSingleString(d *caddyfile.Dispenser) (string, error) {
166
d.Next() // consume parameter name
167
if !d.Next() {
168
return "", d.ArgErr()
@@ -190,11 +178,9 @@ func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
178
if d.Next() {
179
var listenAddress string
180
d.AllArgs(&listenAddress)
193
-
181
if listenAddress == "" {
182
listenAddress = caddy.DefaultAdminListen
183
}
197
-
184
return listenAddress, nil
185
}
186
return "", nil
cmd/commandfuncs.go
+2
-2
@@ -34,7 +34,7 @@ import (
34
35
"github.com/caddyserver/caddy/v2"
36
"github.com/caddyserver/caddy/v2/caddyconfig"
37
- "github.com/mholt/certmagic"
37
+ "github.com/caddyserver/certmagic"
38
"go.uber.org/zap"
39
)
40
@@ -84,7 +84,7 @@ func cmdStart(fl Flags) (int, error) {
84
85
// begin writing the confirmation bytes to the child's
86
// stdin; use a goroutine since the child hasn't been
87
- // started yet, and writing sychronously would result
87
+ // started yet, and writing synchronously would result
88
// in a deadlock
89
go func() {
90
stdinpipe.Write(expect)
cmd/commands.go
+2
@@ -256,6 +256,8 @@ provisioning stages.`,
256
// This function panics if the name is already registered,
257
// if the name does not meet the described format, or if
258
// any of the fields are missing from cmd.
259
+//
260
+// This function should be used in init().
261
func RegisterCommand(cmd Command) {
262
if cmd.Name == "" {
263
panic("command name is required")
context.go
+7
-3
@@ -21,7 +21,7 @@ import (
21
"log"
22
"reflect"
23
24
- "github.com/mholt/certmagic"
24
+ "github.com/caddyserver/certmagic"
25
"go.uber.org/zap"
26
)
27
@@ -384,9 +384,13 @@ func (ctx Context) App(name string) (interface{}, error) {
384
if app, ok := ctx.cfg.apps[name]; ok {
385
return app, nil
386
}
387
- modVal, err := ctx.LoadModuleByID(name, nil)
387
+ appRaw := ctx.cfg.AppsRaw[name]
388
+ modVal, err := ctx.LoadModuleByID(name, appRaw)
389
if err != nil {
389
- return nil, fmt.Errorf("instantiating new module %s: %v", name, err)
390
+ return nil, fmt.Errorf("loading %s app module: %v", name, err)
391
+ }
392
+ if appRaw != nil {
393
+ ctx.cfg.AppsRaw[name] = nil // allow GC to deallocate
394
}
395
ctx.cfg.apps[name] = modVal.(App)
396
return modVal, nil
go.mod
+23
-26
@@ -1,38 +1,35 @@
1
module github.com/caddyserver/caddy/v2
2
3
-go 1.13
3
+go 1.14
4
5
require (
6
- github.com/Masterminds/sprig/v3 v3.0.0
7
- github.com/alecthomas/chroma v0.7.0
8
- github.com/andybalholm/brotli v0.0.0-20190821151343-b60f0d972eeb
9
- github.com/cenkalti/backoff/v3 v3.1.1 // indirect
10
- github.com/dustin/go-humanize v1.0.0
11
- github.com/go-acme/lego/v3 v3.3.0
12
- github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc
6
+ github.com/Masterminds/sprig/v3 v3.0.2
7
+ github.com/alecthomas/chroma v0.7.1
8
+ github.com/andybalholm/brotli v1.0.0
9
+ github.com/caddyserver/certmagic v0.10.0
10
+ github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
11
+ github.com/go-acme/lego/v3 v3.4.0
12
+ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
13
github.com/ilibs/json5 v1.0.1
14
- github.com/imdario/mergo v0.3.8 // indirect
14
github.com/jsternberg/zap-logfmt v1.2.0
16
- github.com/klauspost/compress v1.8.6
17
- github.com/klauspost/cpuid v1.2.2
18
- github.com/kylelemons/godebug v1.1.0 // indirect
19
- github.com/lucas-clemente/quic-go v0.14.4
20
- github.com/mholt/certmagic v0.9.3
21
- github.com/miekg/dns v1.1.25 // indirect
22
- github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190906142622-1265e9b150c6
15
+ github.com/klauspost/compress v1.10.2
16
+ github.com/klauspost/cpuid v1.2.3
17
+ github.com/lucas-clemente/quic-go v0.15.1
18
+ github.com/manifoldco/promptui v0.7.0 // indirect
19
+ github.com/miekg/dns v1.1.27 // indirect
20
+ github.com/muhammadmuzzammil1998/jsonc v0.0.0-20200303171503-1e787b591db7
21
github.com/naoina/go-stringutil v0.1.0 // indirect
22
github.com/naoina/toml v0.1.1
25
- github.com/onsi/ginkgo v1.8.0 // indirect
26
- github.com/onsi/gomega v1.5.0 // indirect
23
+ github.com/smallstep/certificates v0.14.0-rc.5
24
+ github.com/smallstep/cli v0.14.0-rc.3
25
+ github.com/smallstep/truststore v0.9.4
26
github.com/vulcand/oxy v1.0.0
28
- github.com/yuin/goldmark v1.1.17
29
- github.com/yuin/goldmark-highlighting v0.0.0-20191202084645-78f32c8dd6d5
30
- go.uber.org/multierr v1.2.0 // indirect
31
- go.uber.org/zap v1.10.0
32
- golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
33
- golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
34
- golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
27
+ github.com/yuin/goldmark v1.1.24
28
+ github.com/yuin/goldmark-highlighting v0.0.0-20200218065240-d1af22c1126f
29
+ go.uber.org/zap v1.14.0
30
+ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
31
+ golang.org/x/net v0.0.0-20200301022130-244492dfa37a
32
gopkg.in/natefinch/lumberjack.v2 v2.0.0
33
gopkg.in/square/go-jose.v2 v2.4.1 // indirect
37
- gopkg.in/yaml.v2 v2.2.2
34
+ gopkg.in/yaml.v2 v2.2.8
35
)
go.sum
+595
-49
@@ -1,17 +1,30 @@
1
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2
+cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
4
+cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
5
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
6
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
7
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
8
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
9
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
10
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
11
+cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
12
+cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
13
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
14
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
15
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
16
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
17
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
18
+contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
19
+contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
20
+dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
21
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
22
+dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
23
+dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
24
+dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
25
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
26
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
27
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
28
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
29
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
30
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
@@ -30,23 +43,37 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
43
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
44
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
45
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
46
+github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
47
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
48
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
49
+github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
50
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
51
github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=
52
github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
53
+github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
54
+github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
55
github.com/Masterminds/sprig/v3 v3.0.0 h1:KSQz7Nb08/3VU9E4ns29dDxcczhOD1q7O1UfM4G3t3g=
56
github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U=
57
+github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
58
+github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
59
+github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
60
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
61
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
62
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
63
+github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o=
64
+github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
65
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
66
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
67
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
68
+github.com/ThomasRooney/gexpect v0.0.0-20161231170123-5482f0350944/go.mod h1:sPML5WwI6oxLRLPuuqbtoOKhtmpVDCYtwsps+I+vjIY=
69
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k=
70
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
71
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75 h1:3ILjVyslFbc4jl1w5TWuvvslFD/nDfR2H8tVaMVLrEY=
72
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
73
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
74
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
48
-github.com/alecthomas/chroma v0.7.0 h1:z+0HgTUmkpRDRz0SRSdMaqOLfJV4F+N1FPDZUZIDUzw=
49
-github.com/alecthomas/chroma v0.7.0/go.mod h1:1U/PfCsTALWWYHDnsIQkxEBM0+6LLe0v8+RSVMOwxeY=
75
+github.com/alecthomas/chroma v0.7.1 h1:G1i02OhUbRi2nJxcNkwJaY/J1gHXj9tt72qN6ZouLFQ=
76
+github.com/alecthomas/chroma v0.7.1/go.mod h1:gHw09mkX1Qp80JlYbmN9L3+4R5o6DJJ3GRShh+AICNc=
77
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
78
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
79
github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
@@ -55,95 +82,229 @@ github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MR
82
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
83
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
84
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
85
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
86
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
87
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
88
+github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee h1:NYqDBPkhVYt68W3yoGoRRi32i3MLx2ey7SFkJ1v/UI0=
89
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
90
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
61
-github.com/andybalholm/brotli v0.0.0-20190821151343-b60f0d972eeb h1:ZSlUsEd11C/uRzhZHOgANARJ03fkwmjJEa6g2Cqjlo4=
62
-github.com/andybalholm/brotli v0.0.0-20190821151343-b60f0d972eeb/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
91
+github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
92
+github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
93
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
94
+github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
95
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
96
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
97
+github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
98
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
99
+github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
100
+github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
101
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
102
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
103
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
104
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
105
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
69
-github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
70
-github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
71
-github.com/cenkalti/backoff/v3 v3.1.1 h1:UBHElAnr3ODEbpqPzX8g5sBcASjoLFtt3L/xwJ01L6E=
72
-github.com/cenkalti/backoff/v3 v3.1.1/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
106
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
107
+github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U=
108
+github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
109
+github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
110
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
111
+github.com/caddyserver/certmagic v0.10.0 h1:kbQsqN5RmdUMClVUNd8svTzemCo8W6NNc8UJOXnUIu0=
112
+github.com/caddyserver/certmagic v0.10.0/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
113
+github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
114
+github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
115
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
116
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
117
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
118
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
119
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
120
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
121
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
122
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
123
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
124
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
125
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
126
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
127
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
128
github.com/cloudflare/cloudflare-go v0.10.2 h1:VBodKICVPnwmDxstcW3biKcDSpFIfS/RELUXsZSBYK4=
129
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
130
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
131
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
132
+github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
133
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
134
+github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
135
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
136
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
137
+github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
138
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
139
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
140
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
141
+github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
142
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
143
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
144
+github.com/corpix/uarand v0.0.0-20170903190822-2b8494104d86/go.mod h1:JSm890tOkDN+M1jqN8pUGDKnzJrsVbJwSMHBY4zwz7M=
145
+github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
146
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
147
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
148
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
149
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
150
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
151
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
152
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
153
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
154
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
155
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
156
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
157
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
158
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
159
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
160
+github.com/dgraph-io/badger v1.5.3 h1:5oWIuRvwn93cie+OSt1zSnkaIQ1JFQM8bGlIv6O6Sts=
161
+github.com/dgraph-io/badger v1.5.3/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
162
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
163
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
164
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
165
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
166
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
167
github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
168
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
169
+github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
170
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
171
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
172
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
173
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
174
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
175
+github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg=
176
+github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
177
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
178
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
179
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
180
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
181
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
182
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
183
+github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
184
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
185
+github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
186
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
187
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
188
+github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
189
+github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
190
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
191
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
192
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
105
-github.com/go-acme/lego/v3 v3.3.0 h1:6BePZsOiYA4/w+M7QDytxQtMfCipMPGnWAHs9pWks98=
106
-github.com/go-acme/lego/v3 v3.3.0/go.mod h1:iGSY2vQrvQs3WezicSB/oVbO2eCrD88dpWPwb1qLqu0=
193
+github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
194
+github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
195
+github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
196
+github.com/go-chi/chi v3.3.4-0.20181024101233-0ebf7795c516+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
197
+github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
198
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
199
+github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
200
+github.com/go-critic/go-critic v0.4.0/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g=
201
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
202
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
203
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
204
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
205
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
206
+github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
207
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
208
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
209
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
210
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
211
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
212
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
213
+github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
214
+github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
215
+github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
216
+github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
217
+github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
218
+github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
219
+github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
220
+github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
221
+github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
222
+github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
223
+github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
224
+github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
225
+github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
226
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
227
+github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
228
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
229
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
230
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
231
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
232
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
233
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
234
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
235
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
120
-github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc h1:55rEp52jU6bkyslZ1+C/7NGfpQsEc6pxGLAGDOctqbw=
121
-github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
236
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
237
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
238
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
239
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
240
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
241
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
242
+github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
243
+github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
244
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
245
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
246
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
247
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
248
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
249
+github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
250
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
251
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
128
-github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
252
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
253
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
254
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
255
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
256
+github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
257
+github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
258
+github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
259
+github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
260
+github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
261
+github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
262
+github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
263
+github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
264
+github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
265
+github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
266
+github.com/golangci/golangci-lint v1.17.2-0.20190910081718-bad04bb7378f/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg=
267
+github.com/golangci/golangci-lint v1.22.2/go.mod h1:2Bj42k6hPQFTRxkDb7S3TQ+EsnumZXOmIYNqlQrp0FI=
268
+github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU=
269
+github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
270
+github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
271
+github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
272
+github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
273
+github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
274
+github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
275
+github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
276
+github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
277
+github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
278
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
279
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
280
+github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
281
+github.com/google/certificate-transparency-go v1.1.0/go.mod h1:i+Q7XY+ArBveOUT36jiHGfuSK1fHICIg6sUkRxPAbCs=
282
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
283
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
284
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
285
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
286
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
287
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
288
+github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
289
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
290
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
291
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
292
+github.com/google/monologue v0.0.0-20190606152607-4b11a32b5934/go.mod h1:6NTfaQoUpg5QmPsCUWLR3ig33FHrKXhTtWzF0DVdmuk=
293
+github.com/google/monologue v0.0.0-20191220140058-35abc9683a6c/go.mod h1:6NTfaQoUpg5QmPsCUWLR3ig33FHrKXhTtWzF0DVdmuk=
294
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
295
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
296
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
297
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
298
+github.com/google/trillian v1.2.2-0.20190612132142-05461f4df60a/go.mod h1:YPmUVn5NGwgnDUgqlVyFGMTgaWlnSvH7W5p+NdOG8UA=
299
+github.com/google/trillian-examples v0.0.0-20190603134952-4e75ba15216c/go.mod h1:WgL3XZ3pA8/9cm7yxqWrZE6iZkESB2ItGxy5Fo6k2lk=
300
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
301
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
302
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
303
+github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
304
+github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
305
+github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
306
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
307
+github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
308
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
309
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
310
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -154,41 +315,72 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
315
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
316
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
317
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
318
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
319
+github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
320
+github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
321
github.com/gravitational/trace v0.0.0-20190726142706-a535a178675f/go.mod h1:RvdOUHE4SHqR3oXlFFKnGzms8a5dugHygGw1bqDstYI=
322
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
323
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
324
+github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
325
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
326
+github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
327
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
328
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
329
+github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
330
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
331
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
332
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
333
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
334
+github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
335
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
336
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
337
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
338
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
339
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
340
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
341
+github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
342
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
343
github.com/ilibs/json5 v1.0.1 h1:3e14wUQM8PyK6Hf1bM+zAQFxfG+N5oZj35x5vCNeQ58=
344
github.com/ilibs/json5 v1.0.1/go.mod h1:kXsGuzHMPuZZTN15l0IQzy5PR8DrDhPB24tFgwpdKME=
345
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
346
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
347
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
348
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
349
+github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
350
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
351
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
352
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
353
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
354
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
355
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
356
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
357
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
358
+github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
359
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
360
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
361
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
362
github.com/jsternberg/zap-logfmt v1.2.0 h1:1v+PK4/B48cy8cfQbxL4FmmNZrjnIMr2BsnyEmXqv2o=
363
github.com/jsternberg/zap-logfmt v1.2.0/go.mod h1:kz+1CUmCutPWABnNkOu9hOHKdT2q3TDYCcsFy9hpqb0=
364
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
365
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
366
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
367
+github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
368
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
369
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
370
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
371
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
372
+github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
373
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
186
-github.com/klauspost/compress v1.8.6 h1:970MQcQdxX7hfgc/aqmB4a3grW0ivUVV6i1TLkP8CiE=
187
-github.com/klauspost/compress v1.8.6/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
374
+github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
375
+github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
376
+github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0=
377
+github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
378
+github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
379
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
189
-github.com/klauspost/cpuid v1.2.2 h1:1xAgYebNnsb9LKCdLOvFWtAxGU/33mjJtyOVbmUa0Us=
190
-github.com/klauspost/cpuid v1.2.2/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
380
+github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
381
+github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
382
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
383
+github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
384
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
385
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
386
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -196,54 +388,89 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
388
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
389
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
390
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
391
+github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
392
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
393
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
394
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
395
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
396
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
397
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
398
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
399
+github.com/letsencrypt/pkcs11key v2.0.1-0.20170608213348-396559074696+incompatible/go.mod h1:iGYXKqDXt0cpBthCHdr9ZdsQwyGlYFh/+8xa4WzIQ34=
400
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
401
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
402
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
403
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
207
-github.com/lucas-clemente/quic-go v0.14.4 h1:LdXgELrB93kvTqbZyEf+mcsGvmyE+EHsLFz1dqbR5PI=
208
-github.com/lucas-clemente/quic-go v0.14.4/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
404
+github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
405
+github.com/lucas-clemente/quic-go v0.15.1 h1:XB6qeEXGfhveo4t/lClqOcfwravQgyF86DUoVf+YPz0=
406
+github.com/lucas-clemente/quic-go v0.15.1/go.mod h1:qxmO5Y4ZMhdNkunGfxuZnZXnJwYpW9vjQkyrZ7BsgUI=
407
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
408
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
409
+github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
410
+github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
411
+github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
412
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
413
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
414
github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f/go.mod h1:V3EvCedtJTvUYzJF2GZMRB0JMlai+6cBu3VCTQz33GQ=
415
github.com/mailgun/multibuf v0.0.0-20150714184110-565402cd71fb/go.mod h1:E0vRBBIQUHcRtmL/oR6w/jehh4FJqJFxe86gBnw9gXc=
416
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
417
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51/go.mod h1:RYmqHbhWwIz3z9eVmQ2rx82rulEMG0t+Q1bzfc9DYN4=
418
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f/go.mod h1:8heskWJ5c0v5J9WH89ADhyal1DOZcayll8fSbhB+/9A=
214
-github.com/marten-seemann/chacha20 v0.2.0 h1:f40vqzzx+3GdOmzQoItkLX5WLvHgPgyYqFFIO5Gh4hQ=
215
-github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
419
+github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
420
+github.com/manifoldco/promptui v0.3.1/go.mod h1:zoCNXiJnyM03LlBgTsWv8mq28s7aTC71UgKasqRJHww=
421
+github.com/manifoldco/promptui v0.7.0 h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4=
422
+github.com/manifoldco/promptui v0.7.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
423
github.com/marten-seemann/qpack v0.1.0 h1:/0M7lkda/6mus9B8u34Asqm8ZhHAAt9Ho0vniNuVSVg=
424
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
218
-github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gtbkks=
219
-github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
425
+github.com/marten-seemann/qtls v0.8.0 h1:aj+MPLibzKByw8CmG0WvWgbtBkctYPAXeB11cQJC8mo=
426
+github.com/marten-seemann/qtls v0.8.0/go.mod h1:Lao6jDqlCfxyLKYFmZXGm2LSHBgVn+P+ROOex6YkT+k=
427
+github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
428
+github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
429
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
430
+github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
431
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
432
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
433
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
434
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
435
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
436
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
437
+github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
438
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
439
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
440
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
441
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
442
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
443
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
444
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
445
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
228
-github.com/mholt/certmagic v0.9.3 h1:RmzuNJ5mpFplDbyS41z+gGgE/py24IX6m0nHZ0yNTQU=
229
-github.com/mholt/certmagic v0.9.3/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
446
+github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
447
github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI=
448
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
232
-github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
233
-github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
449
+github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
450
+github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
451
+github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
452
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
453
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
454
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
455
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
456
+github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
457
+github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
458
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
459
+github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
460
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
461
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
462
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
463
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
464
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
465
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
466
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
467
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
468
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
245
-github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190906142622-1265e9b150c6 h1:EajWCEv0scxMWyMHWxJbFK70brsPIl4TLQJ0zaOeOiI=
246
-github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190906142622-1265e9b150c6/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
469
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
470
+github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
471
+github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
472
+github.com/muhammadmuzzammil1998/jsonc v0.0.0-20200303171503-1e787b591db7 h1:IhnWtz7gaLvL0wn8xr86ERSvSmwNAsaHMRAqgsu/CVQ=
473
+github.com/muhammadmuzzammil1998/jsonc v0.0.0-20200303171503-1e787b591db7/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
474
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
475
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
476
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
@@ -251,137 +478,344 @@ github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h
478
github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=
479
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
480
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
481
+github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
482
+github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
483
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
484
+github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
485
+github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
486
+github.com/newrelic/go-agent v1.11.0/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
487
+github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
488
+github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
489
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
490
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
256
-github.com/nrdcg/dnspod-go v0.3.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
491
+github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
492
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
493
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
494
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
495
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
496
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
497
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
498
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
499
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
500
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
263
-github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
264
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
501
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
502
+github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
503
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
504
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
505
+github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
506
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
507
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
267
-github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
268
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
508
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
509
+github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
510
+github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
511
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
512
+github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
513
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
514
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
515
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
516
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
517
+github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
518
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
519
+github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
520
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
521
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
522
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
523
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
524
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
525
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
526
+github.com/pquerna/otp v1.0.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
527
+github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
528
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
529
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
530
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
531
+github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM=
532
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
533
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
534
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
535
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
536
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
537
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
538
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
539
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
540
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
541
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
542
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
543
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
544
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
545
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
546
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
547
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
548
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
549
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
550
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
551
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
552
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
553
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
554
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
555
+github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
556
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
557
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
558
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
559
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
560
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
561
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
562
+github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
563
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
564
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
565
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
566
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
567
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
568
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
569
+github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
570
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
571
+github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189 h1:CmSpbxmewNQbzqztaY0bke1qzHhyNyC29wYgh17Gxfo=
572
+github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg=
573
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
574
+github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
575
+github.com/securego/gosec v0.0.0-20200106085552-9cb83e10afad/go.mod h1:7fJLcv5NlMd4t9waQEDLgpZeE3nv4D5DMz5JuZZGufg=
576
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
577
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
578
+github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
579
+github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
580
+github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
581
+github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
582
+github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
583
+github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
584
+github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
585
+github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
586
+github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
587
+github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
588
+github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
589
+github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
590
+github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
591
+github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
592
+github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
593
+github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
594
+github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
595
+github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
596
+github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
597
+github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
598
+github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
599
+github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
600
+github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
601
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
602
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
603
+github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
604
+github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
605
+github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
606
+github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
607
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
608
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
609
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
610
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
611
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
612
+github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE=
613
+github.com/smallstep/assert v0.0.0-20200103212524-b99dc1097b15 h1:kSImCuenAkXtCaBeQ1UhmzzJGRhSm8sVH7I3sHE2Qdg=
614
+github.com/smallstep/assert v0.0.0-20200103212524-b99dc1097b15/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
615
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191023014154-4669bef8c700/go.mod h1:/WOAB2LkcjkEbKG5rDol+A22Lp3UsttkLPLkY7tVtuk=
616
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191025192352-8ef9b020ed24/go.mod h1:043iBnsMvNhQ+QFwSh0N6JR3H2yamHPPAc78vCf+8Tc=
617
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191126035953-e88034bea402/go.mod h1:r2UTcAZNriKlwvNNXymNAcF3iKL6mTYOYrOCtBYYGJU=
618
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191210005525-50152391a397/go.mod h1:8leACUXHFo0JVm9YcrcX09aar2H8hz1BAWxD1D/GpsU=
619
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191213215656-d2100821138c/go.mod h1:HMXt9hWBm7M7ZrUy0uZ/T/077te2x9bnXZCxrdVsBf4=
620
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191217235337-aa5894058226/go.mod h1:MTKifeJBe1B/dzH5NDoPFpIPaWD0MzRozzONVkF8egc=
621
+github.com/smallstep/certificates v0.14.0-rc.1.0.20191218224459-1fa35491ea07/go.mod h1:eEtpedAL4inqaAx6ZqJnE4NOx1/GxDh6VQOmbs7CPf0=
622
+github.com/smallstep/certificates v0.14.0-rc.1.0.20200110185849-085ae821636e/go.mod h1:weY9Os8g0yPfyxd+Zy1CTAwCb7YMqg/u5XnEagBN5Rk=
623
+github.com/smallstep/certificates v0.14.0-rc.1.0.20200111012147-3ce267cdd6b7/go.mod h1:jljUh6mTvHOAqvIUvbD2L3Q/aqSpTI6HzJiNFQkj1Hc=
624
+github.com/smallstep/certificates v0.14.0-rc.1.0.20200128212940-432ed0090f3d/go.mod h1:lWKe0ZOg45lNWtByxh82fOfzXwx93S0TeWzTCOjc19k=
625
+github.com/smallstep/certificates v0.14.0-rc.2.0.20200129195847-7846696fbb69/go.mod h1:vZjJp4hweYVx+rBouWEVOf3KlH2Yilxo/50dsj7y8aY=
626
+github.com/smallstep/certificates v0.14.0-rc.5 h1:AifQ0Agi3FPvcxi+AUkxzjfmj3jGQOd2jKSzpcyhSd0=
627
+github.com/smallstep/certificates v0.14.0-rc.5/go.mod h1:ii3ce5KzeY72D4+f/HBz2rXjgQ9dfpkN8KQRiIxImVM=
628
+github.com/smallstep/certinfo v0.0.0-20191008000228-b0e530932339/go.mod h1:n4YHPL9hJIyB+N4F2rPBy3mpPxMxTGJP5Pdsyaoc2Ns=
629
+github.com/smallstep/certinfo v0.0.0-20191029235839-00563809d483/go.mod h1:xmx5n8+7jI0lrjTUwc8WMMqXeOHRyxYUW9U1wrvP3Vo=
630
+github.com/smallstep/certinfo v1.0.0/go.mod h1:xmx5n8+7jI0lrjTUwc8WMMqXeOHRyxYUW9U1wrvP3Vo=
631
+github.com/smallstep/certinfo v1.1.0/go.mod h1:1gQJekdPwPvUwFWGTi7bZELmQT09cxC9wJ0VBkBNiwU=
632
+github.com/smallstep/cli v0.12.1-0.20191016010425-15911d8625df/go.mod h1:zGPm8vWCqzvDqkdC1laFJNdIOjNSB8V4qDp68Ny538o=
633
+github.com/smallstep/cli v0.13.3 h1:S29UydCtDVy0QQBtGdatq064tnks1/0DYxxnEtNiQpc=
634
+github.com/smallstep/cli v0.13.3/go.mod h1:zGPm8vWCqzvDqkdC1laFJNdIOjNSB8V4qDp68Ny538o=
635
+github.com/smallstep/cli v0.14.0-rc.1.0.20191024214139-914a67ed80c2/go.mod h1:GoA1cE4YrZRRvVbFlPKJUsMuWHnFBX+R88j1pmpbGgk=
636
+github.com/smallstep/cli v0.14.0-rc.1.0.20191105013638-8cf838b56d03/go.mod h1:dklnISxr+GzUmurBngEF9Jvj0aI9KK5uVgZwOdFniNs=
637
+github.com/smallstep/cli v0.14.0-rc.1.0.20191127025104-2821b0b811c1/go.mod h1:F6/cZ7VguiUV4nsoqPdDyZtGOgg3oLHz+LstEQsiSAg=
638
+github.com/smallstep/cli v0.14.0-rc.1.0.20191211225301-a5e848783407/go.mod h1:1DDxP5W6pSuPL7DudNMbr/qVVjToo8qz3tlRt8ka8TA=
639
+github.com/smallstep/cli v0.14.0-rc.1.0.20191217223638-5ee30a55af45/go.mod h1:6pTiWJKfIQcUYtK7lVnI0pOXRiYAWuy0qrlFVnn9q8M=
640
+github.com/smallstep/cli v0.14.0-rc.1.0.20191218000521-3e7348324838/go.mod h1:JPG34JrC37Pw0HjoB+cAtXT1yFOXfab/5nrM7ZTSw8c=
641
+github.com/smallstep/cli v0.14.0-rc.1.0.20200110185014-8a0d0cd3202e/go.mod h1:MA99N6UETSrq7/Pk/iZcgHqqiIU3tDscFNx2pGcdLlU=
642
+github.com/smallstep/cli v0.14.0-rc.1.0.20200111011727-83a91ec8e405/go.mod h1:MCvJvfMNtWCi/VBfXxP1JONqLLfF9TcBj1/t5Rqme90=
643
+github.com/smallstep/cli v0.14.0-rc.1.0.20200127233252-e55637e57819/go.mod h1:SUBVVdOk5XI7yllSupRYHzN5y4MBo89X27CN4P0d+Jw=
644
+github.com/smallstep/cli v0.14.0-rc.1.0.20200128213701-65805ae554f6/go.mod h1:50kmsPMAiR9XD0jHZYY19fkSSD3mKF9ztQjgtTLefjU=
645
+github.com/smallstep/cli v0.14.0-rc.3 h1:IphfrTtJHR2tpFiiBUKfPpO7SCGvfca72PbYJq8k1kU=
646
+github.com/smallstep/cli v0.14.0-rc.3/go.mod h1:5kg85FrLTaQE0JgV3IZAxuVRS7G5qvV0hxOh0u/H6IE=
647
+github.com/smallstep/nosql v0.1.1-0.20191009043502-4b26d8029e61/go.mod h1:MFhYHIE/0V7OOHjYzjnWHqySJ40PVbwhjy24UBkJI2g=
648
+github.com/smallstep/nosql v0.1.1/go.mod h1:qyxCqeyGwkuM6bfJSY3sg+aiXEiD0GbQOPzIF8/ZD8Q=
649
+github.com/smallstep/nosql v0.2.0 h1:IscXK9m9hRyl5GoYgn+Iml//5Bpad3LyIj6R0dZosKM=
650
+github.com/smallstep/nosql v0.2.0/go.mod h1:qyxCqeyGwkuM6bfJSY3sg+aiXEiD0GbQOPzIF8/ZD8Q=
651
+github.com/smallstep/truststore v0.9.3/go.mod h1:PRSkpRIhAYBK/KLWkHNgRdYgzWMEy45bN7PSJCfKKGE=
652
+github.com/smallstep/truststore v0.9.4 h1:HYGtv629TkxRUP63W5R1/9sJGMEL8CrVjIl8z1uvJIM=
653
+github.com/smallstep/truststore v0.9.4/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
654
+github.com/smallstep/zcrypto v0.0.0-20191008000232-9fc4bea33f70/go.mod h1:8LA6x9T22WADMj89Ksf6DnOVCOJF3zLKUdSRAcZmW4U=
655
+github.com/smallstep/zcrypto v0.0.0-20191122194514-76530dff70e7/go.mod h1:8LA6x9T22WADMj89Ksf6DnOVCOJF3zLKUdSRAcZmW4U=
656
+github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4=
657
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
658
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
659
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
660
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
661
+github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
662
+github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
663
+github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
664
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
665
+github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
666
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
667
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
668
+github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
669
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
670
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
671
+github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
672
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
673
+github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
674
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
675
+github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
676
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
677
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
678
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
679
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
680
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
681
+github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
682
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
683
+github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
684
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
685
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
686
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
687
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
688
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
689
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
690
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
691
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
692
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
693
+github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
694
+github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
695
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
696
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
697
+github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
698
+github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
699
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
700
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
701
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
702
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
703
+github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
704
+github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
705
+github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
706
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
707
+github.com/urfave/cli v1.20.1-0.20181029213200-b67dcf995b6a/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
708
+github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
709
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
710
+github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
711
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
712
+github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
713
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
714
+github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
715
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
716
+github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
717
+github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
718
+github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
719
+github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
720
+github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
721
github.com/vulcand/oxy v1.0.0 h1:7vL5/pjDFzHGbtBEhmlHITUi6KLH4xXTDF33/wrdRKw=
722
github.com/vulcand/oxy v1.0.0/go.mod h1:6EXgOAl6CRa46/2ZGcDJKf3ywJUp5WtT7vSlGSkvecI=
723
github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg=
724
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
725
+github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
726
+github.com/weppos/publicsuffix-go v0.10.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
727
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
728
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
729
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
331
-github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
332
-github.com/yuin/goldmark v1.1.17 h1:t7bl7JAmainKs/Uhmr1XZVkRJsgL2UwdTCtTuYL7RAY=
333
-github.com/yuin/goldmark v1.1.17/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
334
-github.com/yuin/goldmark-highlighting v0.0.0-20191202084645-78f32c8dd6d5 h1:QbH7ca1qtgZHrzvcVAEoiJIwBqrXxMOfHYfwZIniIK0=
335
-github.com/yuin/goldmark-highlighting v0.0.0-20191202084645-78f32c8dd6d5/go.mod h1:4QGn5rJFOASBa2uK4Q2h3BRTyJqRfsAucPFIipSTcaM=
730
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
731
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
732
+github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
733
+github.com/yuin/goldmark v1.1.24 h1:K4FemPDr4x/ZcqldoXWnexTLfdMIy2eEfXxsLnotTRI=
734
+github.com/yuin/goldmark v1.1.24/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
735
+github.com/yuin/goldmark-highlighting v0.0.0-20200218065240-d1af22c1126f h1:5295skDVJn90SXIYI22jOMeR9XbnuN76y/V1m9N8ITQ=
736
+github.com/yuin/goldmark-highlighting v0.0.0-20200218065240-d1af22c1126f/go.mod h1:9yW2CHuRSORvHgw7YfybB09PqUZTbzERyW3QFvd8+0Q=
737
+go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
738
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
739
+go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
740
+go.etcd.io/etcd v3.3.18+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
741
+go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
742
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
743
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
744
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
745
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
746
+go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
747
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
748
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
749
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
750
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
751
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
752
+go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
753
+go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
754
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
343
-go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4=
344
-go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
755
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
756
+go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
757
+go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
758
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
759
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
760
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
761
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
762
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
763
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
764
+go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
765
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
766
+go.uber.org/zap v1.14.0 h1:/pduUoebOeeJzTDFuoMgC6nRkiasr1sBCIEorly7m4o=
767
+go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
768
+go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
769
+golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
770
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
771
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
772
+golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
773
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
774
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
775
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
776
+golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
777
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
778
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
779
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
356
-golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
780
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
781
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
782
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
360
-golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
361
-golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
783
+golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
784
+golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
785
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
786
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
787
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
788
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
789
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
790
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
791
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
792
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
793
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
794
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
795
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
796
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
797
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
798
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
799
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
800
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
801
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
802
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
803
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
804
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
805
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
806
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
807
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
808
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
809
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
810
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
811
+golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
812
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
813
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
814
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
815
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
816
+golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
817
+golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
818
+golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
819
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
820
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
821
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -389,21 +823,33 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
823
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
824
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
825
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
826
+golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
827
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
828
+golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
829
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
830
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
831
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
832
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
833
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
834
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
835
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
836
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
837
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
838
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
839
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
840
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
841
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
842
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
843
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
844
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
845
+golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
846
+golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
847
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
848
+golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
849
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
850
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
851
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
852
+golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
853
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
854
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
855
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -412,20 +858,27 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
858
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
859
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
860
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
861
+golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
862
+golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
863
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
864
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
865
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
866
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
867
+golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
868
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
869
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
870
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
871
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
872
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
873
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
874
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
875
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
876
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
877
+golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
878
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
879
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
880
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
881
+golang.org/x/sys v0.0.0-20190424175732-18eb32c0e2f0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
882
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
883
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
884
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -433,76 +886,145 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
886
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
887
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
888
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
436
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
437
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
889
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
890
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
440
-golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
441
-golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
891
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
892
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
893
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
894
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
895
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
896
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e h1:LwyF2AFISC9nVbS6MgzsaQNSUsRXI49GS+YQ5KX/QH0=
897
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
898
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
899
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
900
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
901
+golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
902
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
903
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
904
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
905
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
906
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
907
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
908
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
909
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
910
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
911
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
912
+golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
913
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
914
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
915
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
916
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
917
+golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
918
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
919
+golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
920
+golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
921
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
922
+golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
923
+golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
924
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
925
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
926
+golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
927
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
928
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
929
+golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
930
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
931
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
932
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
933
+golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
934
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
935
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
936
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
937
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
938
+golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
939
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
464
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
940
+golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
941
+golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
942
+golang.org/x/tools v0.0.0-20190911151314-feee8acb394c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
943
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
944
+golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
945
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
946
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
947
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
948
+golang.org/x/tools v0.0.0-20191113232020-e2727e816f5a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
949
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
950
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
951
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
952
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
953
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
954
+golang.org/x/tools v0.0.0-20200106190116-7be0a674c9fc h1:MR2F33ipDGog0C4eMhU6u9o3q6c3dvYis2aG6Jl12Wg=
955
+golang.org/x/tools v0.0.0-20200106190116-7be0a674c9fc/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
956
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
957
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
958
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
959
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
960
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
961
+google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
962
+google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
963
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
964
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
965
+google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
966
+google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
967
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
968
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
969
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
970
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
971
+google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
972
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
973
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
974
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
975
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
976
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
977
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
978
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
979
+google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
980
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
981
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
982
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
983
+google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
984
+google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
985
+google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
986
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
987
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
988
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
989
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
990
+google.golang.org/genproto v0.0.0-20190605220351-eb0b1bdb6ae6/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
991
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
992
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
993
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
994
+google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
995
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
996
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb h1:ADPHZzpzM4tk4V4S5cnCrr5SwzvlrPRmqqCuJDB8UTs=
997
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
998
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
999
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
1000
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
1001
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
1002
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
1003
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
1004
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
1005
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
1006
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
1007
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
1008
+google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
1009
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
1010
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
1011
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
1012
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1013
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
1014
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1015
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
1016
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1017
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
1018
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
1019
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
1020
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
1021
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
1022
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
1023
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
1024
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
1025
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
1026
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
1027
+gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
1028
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
1029
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
1030
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc h1:GAcf+t0o8gdJAdSFYdE9wChu4bIyguMVqz0RHiFL5VY=
@@ -511,6 +1033,7 @@ gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
1033
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
1034
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
1035
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
1036
+gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
1037
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
1038
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
1039
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -519,9 +1042,32 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
1042
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1043
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
1044
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1045
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1046
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1047
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1048
+gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
1049
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1050
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
1051
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1052
+grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
1053
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
1054
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
1055
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
1056
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
1057
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
1058
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
1059
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
1060
+howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=
1061
+howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
1062
+mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
1063
+mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
1064
+mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY=
1065
+mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
1066
+mvdan.cc/unparam v0.0.0-20191111180625-960b1ec0f2c2/go.mod h1:rCqoQrfAmpTX/h2APczwM7UymU/uvaOluiVPIYCSY/k=
1067
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
1068
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
1069
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
1070
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
1071
+sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
1072
+sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
1073
+sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4=
modules.go
+3
-3
@@ -101,7 +101,7 @@ func (id ModuleID) Namespace() string {
101
return string(id)[:lastDot]
102
}
103
104
-// Name returns the Name (last element) of a module name.
104
+// Name returns the Name (last element) of a module ID.
105
func (id ModuleID) Name() string {
106
if id == "" {
107
return ""
@@ -294,8 +294,8 @@ type Provisioner interface {
294
// Validator is implemented by modules which can verify that their
295
// configurations are valid. This method will be called after
296
// Provision() (if implemented). Validation should always be fast
297
-// (imperceptible running time) and an error should be returned only
298
-// if the value's configuration is invalid.
297
+// (imperceptible running time) and an error must be returned if
298
+// the module's configuration is invalid.
299
type Validator interface {
300
Validate() error
301
}
modules/caddyhttp/autohttps.go
+116
-89
@@ -8,7 +8,7 @@ import (
8
9
"github.com/caddyserver/caddy/v2"
10
"github.com/caddyserver/caddy/v2/modules/caddytls"
11
- "github.com/mholt/certmagic"
11
+ "github.com/caddyserver/certmagic"
12
"go.uber.org/zap"
13
)
14
@@ -42,12 +42,10 @@ type AutoHTTPSConfig struct {
42
// enabled. To force automated certificate management
43
// regardless of loaded certificates, set this to true.
44
IgnoreLoadedCerts bool `json:"ignore_loaded_certificates,omitempty"`
45
-
46
- domainSet map[string]struct{}
45
}
46
47
// Skipped returns true if name is in skipSlice, which
50
-// should be one of the Skip* fields on ahc.
48
+// should be either the Skip or SkipCerts field on ahc.
49
func (ahc AutoHTTPSConfig) Skipped(name string, skipSlice []string) bool {
50
for _, n := range skipSlice {
51
if name == n {
@@ -68,6 +66,8 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
66
// addresses to the routes that do HTTP->HTTPS redirects
67
lnAddrRedirRoutes := make(map[string]Route)
68
69
+ uniqueDomainsForCerts := make(map[string]struct{})
70
+
71
for srvName, srv := range app.Servers {
72
// as a prerequisite, provision route matchers; this is
73
// required for all routes on all servers, and must be
@@ -116,8 +116,8 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
116
srv.TLSConnPolicies = defaultConnPolicies
117
}
118
119
- // find all qualifying domain names in this server
120
- srv.AutoHTTPS.domainSet = make(map[string]struct{})
119
+ // find all qualifying domain names (deduplicated) in this server
120
+ serverDomainSet := make(map[string]struct{})
121
for routeIdx, route := range srv.Routes {
122
for matcherSetIdx, matcherSet := range route.MatcherSets {
123
for matcherIdx, m := range matcherSet {
@@ -131,7 +131,7 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
131
}
132
if certmagic.HostQualifies(d) &&
133
!srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.Skip) {
134
- srv.AutoHTTPS.domainSet[d] = struct{}{}
134
+ serverDomainSet[d] = struct{}{}
135
}
136
}
137
}
@@ -141,10 +141,29 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
141
142
// nothing more to do here if there are no
143
// domains that qualify for automatic HTTPS
144
- if len(srv.AutoHTTPS.domainSet) == 0 {
144
+ if len(serverDomainSet) == 0 {
145
continue
146
}
147
148
+ // for all the hostnames we found, filter them so we have
149
+ // a deduplicated list of names for which to obtain certs
150
+ for d := range serverDomainSet {
151
+ if !srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.SkipCerts) {
152
+ // if a certificate for this name is already loaded,
153
+ // don't obtain another one for it, unless we are
154
+ // supposed to ignore loaded certificates
155
+ if !srv.AutoHTTPS.IgnoreLoadedCerts &&
156
+ len(app.tlsApp.AllMatchingCertificates(d)) > 0 {
157
+ app.logger.Info("skipping automatic certificate management because one or more matching certificates are already loaded",
158
+ zap.String("domain", d),
159
+ zap.String("server_name", srvName),
160
+ )
161
+ continue
162
+ }
163
+ uniqueDomainsForCerts[d] = struct{}{}
164
+ }
165
+ }
166
+
167
// tell the server to use TLS if it is not already doing so
168
if srv.TLSConnPolicies == nil {
169
srv.TLSConnPolicies = defaultConnPolicies
@@ -209,6 +228,19 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
228
}
229
}
230
231
+ // we now have a list of all the unique names for which we need certs;
232
+ // turn the set into a slice so that phase 2 can use it
233
+ app.allCertDomains = make([]string, 0, len(uniqueDomainsForCerts))
234
+ for d := range uniqueDomainsForCerts {
235
+ app.allCertDomains = append(app.allCertDomains, d)
236
+ }
237
+
238
+ // ensure there is an automation policy to handle these certs
239
+ err := app.createAutomationPolicy(ctx)
240
+ if err != nil {
241
+ return err
242
+ }
243
+
244
// if there are HTTP->HTTPS redirects to add, do so now
245
if len(lnAddrRedirRoutes) == 0 {
246
return nil
@@ -258,28 +290,78 @@ redirRoutesLoop:
290
return nil
291
}
292
261
-// automaticHTTPSPhase2 attaches a TLS app pointer to each
262
-// server. This phase must occur after provisioning, and
263
-// at the beginning of the app start, before starting each
264
-// of the servers.
265
-func (app *App) automaticHTTPSPhase2() error {
266
- tlsAppIface, err := app.ctx.App("tls")
267
- if err != nil {
268
- return fmt.Errorf("getting tls app: %v", err)
293
+// createAutomationPolicy ensures that certificates for this app are
294
+// managed properly; for example, it's implied that the HTTPPort
295
+// should also be the port the HTTP challenge is solved on; the same
296
+// for HTTPS port and TLS-ALPN challenge also. We need to tell the
297
+// TLS app to manage these certs by honoring those port configurations,
298
+// so we either find an existing matching automation policy with an
299
+// ACME issuer, or make a new one and append it.
300
+func (app *App) createAutomationPolicy(ctx caddy.Context) error {
301
+ var matchingPolicy *caddytls.AutomationPolicy
302
+ var acmeIssuer *caddytls.ACMEIssuer
303
+ if app.tlsApp.Automation != nil {
304
+ // maybe we can find an exisitng one that matches; this is
305
+ // useful if the user made a single automation policy to
306
+ // set the CA endpoint to a test/staging endpoint (very
307
+ // common), but forgot to customize the ports here, while
308
+ // setting them in the HTTP app instead (I did this too
309
+ // many times)
310
+ for _, ap := range app.tlsApp.Automation.Policies {
311
+ if len(ap.Hosts) == 0 {
312
+ matchingPolicy = ap
313
+ break
314
+ }
315
+ }
316
+ }
317
+ if matchingPolicy != nil {
318
+ // if it has an ACME issuer, maybe we can just use that
319
+ acmeIssuer, _ = matchingPolicy.Issuer.(*caddytls.ACMEIssuer)
320
+ }
321
+ if acmeIssuer.Challenges == nil {
322
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
323
+ }
324
+ if acmeIssuer.Challenges.HTTP == nil {
325
+ acmeIssuer.Challenges.HTTP = new(caddytls.HTTPChallengeConfig)
326
+ }
327
+ if acmeIssuer.Challenges.HTTP.AlternatePort == 0 {
328
+ // don't overwrite existing explicit config
329
+ acmeIssuer.Challenges.HTTP.AlternatePort = app.HTTPPort
330
+ }
331
+ if acmeIssuer.Challenges.TLSALPN == nil {
332
+ acmeIssuer.Challenges.TLSALPN = new(caddytls.TLSALPNChallengeConfig)
333
+ }
334
+ if acmeIssuer.Challenges.TLSALPN.AlternatePort == 0 {
335
+ // don't overwrite existing explicit config
336
+ acmeIssuer.Challenges.TLSALPN.AlternatePort = app.HTTPSPort
337
}
270
- tlsApp := tlsAppIface.(*caddytls.TLS)
338
272
- // set the tlsApp pointer before starting any
273
- // challenges, since it is required to solve
274
- // the ACME HTTP challenge
275
- for _, srv := range app.Servers {
276
- srv.tlsApp = tlsApp
339
+ if matchingPolicy == nil {
340
+ // if there was no matching policy, we'll have to append our own
341
+ err := app.tlsApp.AddAutomationPolicy(&caddytls.AutomationPolicy{
342
+ Hosts: app.allCertDomains,
343
+ Issuer: acmeIssuer,
344
+ })
345
+ if err != nil {
346
+ return err
347
+ }
348
+ } else {
349
+ // if there was an existing matching policy, we need to reprovision
350
+ // its issuer (because we just changed its port settings and it has
351
+ // to re-build its stored certmagic config template with the new
352
+ // values), then re-assign the Issuer pointer on the policy struct
353
+ // because our type assertion changed the address
354
+ err := acmeIssuer.Provision(ctx)
355
+ if err != nil {
356
+ return err
357
+ }
358
+ matchingPolicy.Issuer = acmeIssuer
359
}
360
361
return nil
362
}
363
282
-// automaticHTTPSPhase3 begins certificate management for
364
+// automaticHTTPSPhase2 begins certificate management for
365
// all names in the qualifying domain set for each server.
366
// This phase must occur after provisioning and at the end
367
// of app start, after all the servers have been started.
@@ -289,72 +371,17 @@ func (app *App) automaticHTTPSPhase2() error {
371
// first, then our servers would fail to bind to them,
372
// which would be bad, since CertMagic's bindings are
373
// temporary and don't serve the user's sites!).
292
-func (app *App) automaticHTTPSPhase3() error {
293
- // begin managing certificates for enabled servers
294
- for srvName, srv := range app.Servers {
295
- if srv.AutoHTTPS == nil ||
296
- srv.AutoHTTPS.Disabled ||
297
- len(srv.AutoHTTPS.domainSet) == 0 {
298
- continue
299
- }
300
-
301
- // marshal the domains into a slice
302
- var domains, domainsForCerts []string
303
- for d := range srv.AutoHTTPS.domainSet {
304
- domains = append(domains, d)
305
- if !srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.SkipCerts) {
306
- // if a certificate for this name is already loaded,
307
- // don't obtain another one for it, unless we are
308
- // supposed to ignore loaded certificates
309
- if !srv.AutoHTTPS.IgnoreLoadedCerts &&
310
- len(srv.tlsApp.AllMatchingCertificates(d)) > 0 {
311
- app.logger.Info("skipping automatic certificate management because one or more matching certificates are already loaded",
312
- zap.String("domain", d),
313
- zap.String("server_name", srvName),
314
- )
315
- continue
316
- }
317
- domainsForCerts = append(domainsForCerts, d)
318
- }
319
- }
320
-
321
- // ensure that these certificates are managed properly;
322
- // for example, it's implied that the HTTPPort should also
323
- // be the port the HTTP challenge is solved on, and so
324
- // for HTTPS port and TLS-ALPN challenge also - we need
325
- // to tell the TLS app to manage these certs by honoring
326
- // those port configurations
327
- acmeManager := &caddytls.ACMEManagerMaker{
328
- Challenges: &caddytls.ChallengesConfig{
329
- HTTP: &caddytls.HTTPChallengeConfig{
330
- AlternatePort: app.HTTPPort, // we specifically want the user-configured port, if any
331
- },
332
- TLSALPN: &caddytls.TLSALPNChallengeConfig{
333
- AlternatePort: app.HTTPSPort, // we specifically want the user-configured port, if any
334
- },
335
- },
336
- }
337
- if srv.tlsApp.Automation == nil {
338
- srv.tlsApp.Automation = new(caddytls.AutomationConfig)
339
- }
340
- srv.tlsApp.Automation.Policies = append(srv.tlsApp.Automation.Policies,
341
- &caddytls.AutomationPolicy{
342
- Hosts: domainsForCerts,
343
- Management: acmeManager,
344
- })
345
-
346
- // manage their certificates
347
- app.logger.Info("enabling automatic TLS certificate management",
348
- zap.Strings("domains", domainsForCerts),
349
- )
350
- err := srv.tlsApp.Manage(domainsForCerts)
351
- if err != nil {
352
- return fmt.Errorf("%s: managing certificate for %s: %s", srvName, domains, err)
353
- }
354
-
355
- // no longer needed; allow GC to deallocate
356
- srv.AutoHTTPS.domainSet = nil
374
+func (app *App) automaticHTTPSPhase2() error {
375
+ if len(app.allCertDomains) == 0 {
376
+ return nil
377
}
358
-
378
+ app.logger.Info("enabling automatic TLS certificate management",
379
+ zap.Strings("domains", app.allCertDomains),
380
+ )
381
+ err := app.tlsApp.Manage(app.allCertDomains)
382
+ if err != nil {
383
+ return fmt.Errorf("managing certificates for %v: %s", app.allCertDomains, err)
384
+ }
385
+ app.allCertDomains = nil // no longer needed; allow GC to deallocate
386
return nil
387
}
modules/caddyhttp/caddyhttp.go
+32
-15
@@ -28,6 +28,7 @@ import (
28
"time"
29
30
"github.com/caddyserver/caddy/v2"
31
+ "github.com/caddyserver/caddy/v2/modules/caddytls"
32
"github.com/lucas-clemente/quic-go/http3"
33
"go.uber.org/zap"
34
)
@@ -71,6 +72,16 @@ func init() {
72
// `{http.request.remote.port}` | The port part of the remote client's address
73
// `{http.request.remote}` | The address of the remote client
74
// `{http.request.scheme}` | The request scheme
75
+// `{http.request.tls.version}` | The TLS version name
76
+// `{http.request.tls.cipher_suite}` | The TLS cipher suite
77
+// `{http.request.tls.resumed}` | The TLS connection resumed a previous connection
78
+// `{http.request.tls.proto}` | The negotiated next protocol
79
+// `{http.request.tls.proto_mutual}` | The negotiated next protocol was advertised by the server
80
+// `{http.request.tls.server_name}` | The server name requested by the client, if any
81
+// `{http.request.tls.client.fingerprint}` | The SHA256 checksum of the client certificate
82
+// `{http.request.tls.client.issuer}` | The issuer DN of the client certificate
83
+// `{http.request.tls.client.serial}` | The serial number of the client certificate
84
+// `{http.request.tls.client.subject}` | The subject DN of the client certificate
85
// `{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left)
86
// `{http.request.uri.path.dir}` | The directory, excluding leaf filename
87
// `{http.request.uri.path.file}` | The filename of the path, excluding directory
@@ -107,6 +118,10 @@ type App struct {
118
119
ctx caddy.Context
120
logger *zap.Logger
121
+ tlsApp *caddytls.TLS
122
+
123
+ // used temporarily between phases 1 and 2 of auto HTTPS
124
+ allCertDomains []string
125
}
126
127
// CaddyModule returns the Caddy module information.
@@ -119,6 +134,12 @@ func (App) CaddyModule() caddy.ModuleInfo {
134
135
// Provision sets up the app.
136
func (app *App) Provision(ctx caddy.Context) error {
137
+ // store some references
138
+ tlsAppIface, err := ctx.App("tls")
139
+ if err != nil {
140
+ return fmt.Errorf("getting tls app: %v", err)
141
+ }
142
+ app.tlsApp = tlsAppIface.(*caddytls.TLS)
143
app.ctx = ctx
144
app.logger = ctx.Logger(app)
145
@@ -127,12 +148,14 @@ func (app *App) Provision(ctx caddy.Context) error {
148
// this provisions the matchers for each route,
149
// and prepares auto HTTP->HTTP redirects, and
150
// is required before we provision each server
130
- err := app.automaticHTTPSPhase1(ctx, repl)
151
+ err = app.automaticHTTPSPhase1(ctx, repl)
152
if err != nil {
153
return err
154
}
155
156
+ // prepare each server
157
for srvName, srv := range app.Servers {
158
+ srv.tlsApp = app.tlsApp
159
srv.logger = app.logger.Named("log")
160
srv.errorLogger = app.logger.Named("log.error")
161
@@ -185,9 +208,14 @@ func (app *App) Provision(ctx caddy.Context) error {
208
if err != nil {
209
return fmt.Errorf("server %s: setting up server error handling routes: %v", srvName, err)
210
}
188
-
211
srv.errorHandlerChain = srv.Errors.Routes.Compile(errorEmptyHandler)
212
}
213
+
214
+ // prepare the TLS connection policies
215
+ err = srv.TLSConnPolicies.Provision(ctx)
216
+ if err != nil {
217
+ return fmt.Errorf("server %s: setting up TLS connection policies: %v", srvName, err)
218
+ }
219
}
220
221
return nil
@@ -221,14 +249,6 @@ func (app *App) Validate() error {
249
// Start runs the app. It finishes automatic HTTPS if enabled,
250
// including management of certificates.
251
func (app *App) Start() error {
224
- // give each server a pointer to the TLS app;
225
- // this is required before they are started so
226
- // they can solve ACME challenges
227
- err := app.automaticHTTPSPhase2()
228
- if err != nil {
229
- return fmt.Errorf("enabling automatic HTTPS, phase 2: %v", err)
230
- }
231
-
252
for srvName, srv := range app.Servers {
253
s := &http.Server{
254
ReadTimeout: time.Duration(srv.ReadTimeout),
@@ -262,10 +282,7 @@ func (app *App) Start() error {
282
if len(srv.TLSConnPolicies) > 0 &&
283
int(listenAddr.StartPort+portOffset) != app.httpPort() {
284
// create TLS listener
265
- tlsCfg, err := srv.TLSConnPolicies.TLSConfig(app.ctx)
266
- if err != nil {
267
- return fmt.Errorf("%s/%s: making TLS configuration: %v", listenAddr.Network, hostport, err)
268
- }
285
+ tlsCfg := srv.TLSConnPolicies.TLSConfig(app.ctx)
286
ln = tls.NewListener(ln, tlsCfg)
287
288
/////////
@@ -301,7 +318,7 @@ func (app *App) Start() error {
318
319
// finish automatic HTTPS by finally beginning
320
// certificate management
304
- err = app.automaticHTTPSPhase3()
321
+ err := app.automaticHTTPSPhase2()
322
if err != nil {
323
return fmt.Errorf("finalizing automatic HTTPS: %v", err)
324
}
modules/caddyhttp/fileserver/command.go
+1
-1
@@ -26,7 +26,7 @@ import (
26
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
27
caddycmd "github.com/caddyserver/caddy/v2/cmd"
28
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
29
- "github.com/mholt/certmagic"
29
+ "github.com/caddyserver/certmagic"
30
)
31
32
func init() {
modules/caddyhttp/httpcache/httpcache.go
+9
-3
@@ -16,6 +16,7 @@ package httpcache
16
17
import (
18
"bytes"
19
+ "context"
20
"encoding/gob"
21
"fmt"
22
"io"
@@ -108,7 +109,8 @@ func (c *Cache) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp
109
return next.ServeHTTP(w, r)
110
}
111
111
- ctx := getterContext{w, r, next}
112
+ getterCtx := getterContext{w, r, next}
113
+ ctx := context.WithValue(r.Context(), getterContextCtxKey, getterCtx)
114
115
// TODO: rigorous performance testing
116
@@ -152,8 +154,8 @@ func (c *Cache) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp
154
return nil
155
}
156
155
-func (c *Cache) getter(ctx groupcache.Context, key string, dest groupcache.Sink) error {
156
- combo := ctx.(getterContext)
157
+func (c *Cache) getter(ctx context.Context, key string, dest groupcache.Sink) error {
158
+ combo := ctx.Value(getterContextCtxKey).(getterContext)
159
160
// the buffer will store the gob-encoded header, then the body
161
buf := bufPool.Get().(*bytes.Buffer)
@@ -228,6 +230,10 @@ var errUncacheable = fmt.Errorf("uncacheable")
230
231
const groupName = "http_requests"
232
233
+type ctxKey string
234
+
235
+const getterContextCtxKey ctxKey = "getter_context"
236
+
237
// Interface guards
238
var (
239
_ caddy.Provisioner = (*Cache)(nil)
modules/caddyhttp/replacer.go
+89
-15
@@ -15,6 +15,9 @@
15
package caddyhttp
16
17
import (
18
+ "crypto/sha256"
19
+ "crypto/tls"
20
+ "crypto/x509"
21
"fmt"
22
"net"
23
"net/http"
@@ -24,14 +27,15 @@ import (
27
"strings"
28
29
"github.com/caddyserver/caddy/v2"
30
+ "github.com/caddyserver/caddy/v2/modules/caddytls"
31
)
32
33
func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.ResponseWriter) {
34
httpVars := func(key string) (string, bool) {
35
if req != nil {
36
// query string parameters
33
- if strings.HasPrefix(key, queryReplPrefix) {
34
- vals := req.URL.Query()[key[len(queryReplPrefix):]]
37
+ if strings.HasPrefix(key, reqURIQueryReplPrefix) {
38
+ vals := req.URL.Query()[key[len(reqURIQueryReplPrefix):]]
39
// always return true, since the query param might
40
// be present only in some requests
41
return strings.Join(vals, ","), true
@@ -47,8 +51,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
51
}
52
53
// cookies
50
- if strings.HasPrefix(key, cookieReplPrefix) {
51
- name := key[len(cookieReplPrefix):]
54
+ if strings.HasPrefix(key, reqCookieReplPrefix) {
55
+ name := key[len(reqCookieReplPrefix):]
56
for _, cookie := range req.Cookies() {
57
if strings.EqualFold(name, cookie.Name) {
58
// always return true, since the cookie might
@@ -58,6 +62,11 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
62
}
63
}
64
65
+ // http.request.tls.
66
+ if strings.HasPrefix(key, reqTLSReplPrefix) {
67
+ return getReqTLSReplacement(req, key)
68
+ }
69
+
70
switch key {
71
case "http.request.method":
72
return req.Method, true
@@ -129,8 +138,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
138
}
139
140
// hostname labels
132
- if strings.HasPrefix(key, hostLabelReplPrefix) {
133
- idxStr := key[len(hostLabelReplPrefix):]
141
+ if strings.HasPrefix(key, reqHostLabelsReplPrefix) {
142
+ idxStr := key[len(reqHostLabelsReplPrefix):]
143
idx, err := strconv.Atoi(idxStr)
144
if err != nil {
145
return "", false
@@ -150,8 +159,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
159
}
160
161
// path parts
153
- if strings.HasPrefix(key, pathPartsReplPrefix) {
154
- idxStr := key[len(pathPartsReplPrefix):]
162
+ if strings.HasPrefix(key, reqURIPathReplPrefix) {
163
+ idxStr := key[len(reqURIPathReplPrefix):]
164
idx, err := strconv.Atoi(idxStr)
165
if err != nil {
166
return "", false
@@ -208,12 +217,77 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
217
repl.Map(httpVars)
218
}
219
220
+func getReqTLSReplacement(req *http.Request, key string) (string, bool) {
221
+ if req == nil || req.TLS == nil {
222
+ return "", false
223
+ }
224
+
225
+ if len(key) < len(reqTLSReplPrefix) {
226
+ return "", false
227
+ }
228
+
229
+ field := strings.ToLower(key[len(reqTLSReplPrefix):])
230
+
231
+ if strings.HasPrefix(field, "client.") {
232
+ cert := getTLSPeerCert(req.TLS)
233
+ if cert == nil {
234
+ return "", false
235
+ }
236
+
237
+ switch field {
238
+ case "client.fingerprint":
239
+ return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
240
+ case "client.issuer":
241
+ return cert.Issuer.String(), true
242
+ case "client.serial":
243
+ return fmt.Sprintf("%x", cert.SerialNumber), true
244
+ case "client.subject":
245
+ return cert.Subject.String(), true
246
+ default:
247
+ return "", false
248
+ }
249
+ }
250
+
251
+ switch field {
252
+ case "version":
253
+ return caddytls.ProtocolName(req.TLS.Version), true
254
+ case "cipher_suite":
255
+ return tls.CipherSuiteName(req.TLS.CipherSuite), true
256
+ case "resumed":
257
+ if req.TLS.DidResume {
258
+ return "true", true
259
+ }
260
+ return "false", true
261
+ case "proto":
262
+ return req.TLS.NegotiatedProtocol, true
263
+ case "proto_mutual":
264
+ if req.TLS.NegotiatedProtocolIsMutual {
265
+ return "true", true
266
+ }
267
+ return "false", true
268
+ case "server_name":
269
+ return req.TLS.ServerName, true
270
+ default:
271
+ return "", false
272
+ }
273
+}
274
+
275
+// getTLSPeerCert retrieves the first peer certificate from a TLS session.
276
+// Returns nil if no peer cert is in use.
277
+func getTLSPeerCert(cs *tls.ConnectionState) *x509.Certificate {
278
+ if len(cs.PeerCertificates) == 0 {
279
+ return nil
280
+ }
281
+ return cs.PeerCertificates[0]
282
+}
283
+
284
const (
212
- queryReplPrefix = "http.request.uri.query."
213
- reqHeaderReplPrefix = "http.request.header."
214
- cookieReplPrefix = "http.request.cookie."
215
- hostLabelReplPrefix = "http.request.host.labels."
216
- pathPartsReplPrefix = "http.request.uri.path."
217
- varsReplPrefix = "http.vars."
218
- respHeaderReplPrefix = "http.response.header."
285
+ reqCookieReplPrefix = "http.request.cookie."
286
+ reqHeaderReplPrefix = "http.request.header."
287
+ reqHostLabelsReplPrefix = "http.request.host.labels."
288
+ reqTLSReplPrefix = "http.request.tls."
289
+ reqURIPathReplPrefix = "http.request.uri.path."
290
+ reqURIQueryReplPrefix = "http.request.uri.query."
291
+ respHeaderReplPrefix = "http.response.header."
292
+ varsReplPrefix = "http.vars."
293
)
modules/caddyhttp/replacer_test.go
+79
-1
@@ -16,6 +16,9 @@ package caddyhttp
16
17
import (
18
"context"
19
+ "crypto/tls"
20
+ "crypto/x509"
21
+ "encoding/pem"
22
"net/http"
23
"net/http/httptest"
24
"testing"
@@ -30,6 +33,41 @@ func TestHTTPVarReplacement(t *testing.T) {
33
req = req.WithContext(ctx)
34
req.Host = "example.com:80"
35
req.RemoteAddr = "localhost:1234"
36
+
37
+ clientCert := []byte(`-----BEGIN CERTIFICATE-----
38
+MIIB9jCCAV+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1DYWRk
39
+eSBUZXN0IENBMB4XDTE4MDcyNDIxMzUwNVoXDTI4MDcyMTIxMzUwNVowHTEbMBkG
40
+A1UEAwwSY2xpZW50LmxvY2FsZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
41
+iQKBgQDFDEpzF0ew68teT3xDzcUxVFaTII+jXH1ftHXxxP4BEYBU4q90qzeKFneF
42
+z83I0nC0WAQ45ZwHfhLMYHFzHPdxr6+jkvKPASf0J2v2HDJuTM1bHBbik5Ls5eq+
43
+fVZDP8o/VHKSBKxNs8Goc2NTsr5b07QTIpkRStQK+RJALk4x9QIDAQABo0swSTAJ
44
+BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8A
45
+AAEwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADgYEANSjz2Sk+
46
+eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
47
+3Q9fgDkiUod+uIK0IynzIKvw+Cjg+3nx6NQ0IM0zo8c7v398RzB4apbXKZyeeqUH
48
+9fNwfEi+OoXR6s+upSKobCmLGLGi9Na5s5g=
49
+-----END CERTIFICATE-----`)
50
+
51
+ block, _ := pem.Decode(clientCert)
52
+ if block == nil {
53
+ t.Fatalf("failed to decode PEM certificate")
54
+ }
55
+
56
+ cert, err := x509.ParseCertificate(block.Bytes)
57
+ if err != nil {
58
+ t.Fatalf("failed to decode PEM certificate: %v", err)
59
+ }
60
+
61
+ req.TLS = &tls.ConnectionState{
62
+ Version: tls.VersionTLS13,
63
+ HandshakeComplete: true,
64
+ ServerName: "foo.com",
65
+ CipherSuite: tls.TLS_AES_256_GCM_SHA384,
66
+ PeerCertificates: []*x509.Certificate{cert},
67
+ NegotiatedProtocol: "h2",
68
+ NegotiatedProtocolIsMutual: true,
69
+ }
70
+
71
res := httptest.NewRecorder()
72
addHTTPVarsToReplacer(repl, req, res)
73
@@ -39,7 +77,7 @@ func TestHTTPVarReplacement(t *testing.T) {
77
}{
78
{
79
input: "{http.request.scheme}",
42
- expect: "http",
80
+ expect: "https",
81
},
82
{
83
input: "{http.request.host}",
@@ -69,6 +107,46 @@ func TestHTTPVarReplacement(t *testing.T) {
107
input: "{http.request.host.labels.1}",
108
expect: "example",
109
},
110
+ {
111
+ input: "{http.request.tls.cipher_suite}",
112
+ expect: "TLS_AES_256_GCM_SHA384",
113
+ },
114
+ {
115
+ input: "{http.request.tls.proto}",
116
+ expect: "h2",
117
+ },
118
+ {
119
+ input: "{http.request.tls.proto_mutual}",
120
+ expect: "true",
121
+ },
122
+ {
123
+ input: "{http.request.tls.resumed}",
124
+ expect: "false",
125
+ },
126
+ {
127
+ input: "{http.request.tls.server_name}",
128
+ expect: "foo.com",
129
+ },
130
+ {
131
+ input: "{http.request.tls.version}",
132
+ expect: "tls1.3",
133
+ },
134
+ {
135
+ input: "{http.request.tls.client.fingerprint}",
136
+ expect: "9f57b7b497cceacc5459b76ac1c3afedbc12b300e728071f55f84168ff0f7702",
137
+ },
138
+ {
139
+ input: "{http.request.tls.client.issuer}",
140
+ expect: "CN=Caddy Test CA",
141
+ },
142
+ {
143
+ input: "{http.request.tls.client.serial}",
144
+ expect: "2",
145
+ },
146
+ {
147
+ input: "{http.request.tls.client.subject}",
148
+ expect: "CN=client.localdomain",
149
+ },
150
} {
151
actual := repl.ReplaceAll(tc.input, "<empty>")
152
if actual != tc.expect {
modules/caddyhttp/reverseproxy/command.go
+1
-1
@@ -29,7 +29,7 @@ import (
29
caddycmd "github.com/caddyserver/caddy/v2/cmd"
30
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
31
"github.com/caddyserver/caddy/v2/modules/caddyhttp/headers"
32
- "github.com/mholt/certmagic"
32
+ "github.com/caddyserver/certmagic"
33
)
34
35
func init() {
modules/caddyhttp/server.go
+1
-1
@@ -173,7 +173,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
173
}
174
175
log("handled request",
176
- zap.String("common_log", repl.ReplaceAll(commonLogFormat, "-")),
176
+ zap.String("common_log", repl.ReplaceAll(commonLogFormat, commonLogEmptyValue)),
177
zap.Duration("latency", latency),
178
zap.Int("size", wrec.Size()),
179
zap.Int("status", wrec.Status()),
modules/caddytls/acmeissuer.go
new
+207
@@ -0,0 +1,207 @@
1
+// Copyright 2015 Matthew Holt and The Caddy Authors
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License");
4
+// you may not use this file except in compliance with the License.
5
+// You may obtain a copy of the License at
6
+//
7
+// http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS,
11
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+// See the License for the specific language governing permissions and
13
+// limitations under the License.
14
+
15
+package caddytls
16
+
17
+import (
18
+ "context"
19
+ "crypto/x509"
20
+ "fmt"
21
+ "io/ioutil"
22
+ "net/url"
23
+ "time"
24
+
25
+ "github.com/caddyserver/caddy/v2"
26
+ "github.com/caddyserver/certmagic"
27
+ "github.com/go-acme/lego/v3/challenge"
28
+)
29
+
30
+func init() {
31
+ caddy.RegisterModule(ACMEIssuer{})
32
+}
33
+
34
+// ACMEIssuer makes an ACME manager
35
+// for managing certificates using ACME.
36
+//
37
+// TODO: support multiple ACME endpoints (probably
38
+// requires an array of these structs) - caddy would
39
+// also have to load certs from the backup CAs if the
40
+// first one is expired...
41
+type ACMEIssuer struct {
42
+ // The URL to the CA's ACME directory endpoint.
43
+ CA string `json:"ca,omitempty"`
44
+
45
+ // The URL to the test CA's ACME directory endpoint.
46
+ // This endpoint is only used during retries if there
47
+ // is a failure using the primary CA.
48
+ TestCA string `json:"test_ca,omitempty"`
49
+
50
+ // Your email address, so the CA can contact you if necessary.
51
+ // Not required, but strongly recommended to provide one so
52
+ // you can be reached if there is a problem. Your email is
53
+ // not sent to any Caddy mothership or used for any purpose
54
+ // other than ACME transactions.
55
+ Email string `json:"email,omitempty"`
56
+
57
+ // Time to wait before timing out an ACME operation.
58
+ ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"`
59
+
60
+ // Configures the various ACME challenge types.
61
+ Challenges *ChallengesConfig `json:"challenges,omitempty"`
62
+
63
+ // An array of files of CA certificates to accept when connecting to the
64
+ // ACME CA. Generally, you should only use this if the ACME CA endpoint
65
+ // is internal or for development/testing purposes.
66
+ TrustedRootsPEMFiles []string `json:"trusted_roots_pem_files,omitempty"`
67
+
68
+ rootPool *x509.CertPool
69
+ template certmagic.ACMEManager
70
+ magic *certmagic.Config
71
+}
72
+
73
+// CaddyModule returns the Caddy module information.
74
+func (ACMEIssuer) CaddyModule() caddy.ModuleInfo {
75
+ return caddy.ModuleInfo{
76
+ ID: "tls.issuance.acme",
77
+ New: func() caddy.Module { return new(ACMEIssuer) },
78
+ }
79
+}
80
+
81
+// Provision sets up m.
82
+func (m *ACMEIssuer) Provision(ctx caddy.Context) error {
83
+ // DNS providers
84
+ if m.Challenges != nil && m.Challenges.DNSRaw != nil {
85
+ val, err := ctx.LoadModule(m.Challenges, "DNSRaw")
86
+ if err != nil {
87
+ return fmt.Errorf("loading DNS provider module: %v", err)
88
+ }
89
+ prov, err := val.(DNSProviderMaker).NewDNSProvider()
90
+ if err != nil {
91
+ return fmt.Errorf("making DNS provider: %v", err)
92
+ }
93
+ m.Challenges.DNS = prov
94
+ }
95
+
96
+ // add any custom CAs to trust store
97
+ if len(m.TrustedRootsPEMFiles) > 0 {
98
+ m.rootPool = x509.NewCertPool()
99
+ for _, pemFile := range m.TrustedRootsPEMFiles {
100
+ pemData, err := ioutil.ReadFile(pemFile)
101
+ if err != nil {
102
+ return fmt.Errorf("loading trusted root CA's PEM file: %s: %v", pemFile, err)
103
+ }
104
+ if !m.rootPool.AppendCertsFromPEM(pemData) {
105
+ return fmt.Errorf("unable to add %s to trust pool: %v", pemFile, err)
106
+ }
107
+ }
108
+ }
109
+
110
+ m.template = m.makeIssuerTemplate()
111
+
112
+ return nil
113
+}
114
+
115
+func (m *ACMEIssuer) makeIssuerTemplate() certmagic.ACMEManager {
116
+ template := certmagic.ACMEManager{
117
+ CA: m.CA,
118
+ Email: m.Email,
119
+ Agreed: true,
120
+ CertObtainTimeout: time.Duration(m.ACMETimeout),
121
+ TrustedRoots: m.rootPool,
122
+ }
123
+
124
+ if m.Challenges != nil {
125
+ if m.Challenges.HTTP != nil {
126
+ template.DisableHTTPChallenge = m.Challenges.HTTP.Disabled
127
+ template.AltHTTPPort = m.Challenges.HTTP.AlternatePort
128
+ }
129
+ if m.Challenges.TLSALPN != nil {
130
+ template.DisableTLSALPNChallenge = m.Challenges.TLSALPN.Disabled
131
+ template.AltTLSALPNPort = m.Challenges.TLSALPN.AlternatePort
132
+ }
133
+ template.DNSProvider = m.Challenges.DNS
134
+ }
135
+
136
+ return template
137
+}
138
+
139
+// SetConfig sets the associated certmagic config for this issuer.
140
+// This is required because ACME needs values from the config in
141
+// order to solve the challenges during issuance. This implements
142
+// the ConfigSetter interface.
143
+func (m *ACMEIssuer) SetConfig(cfg *certmagic.Config) {
144
+ m.magic = cfg
145
+}
146
+
147
+// PreCheck implements the certmagic.PreChecker interface.
148
+func (m *ACMEIssuer) PreCheck(names []string, interactive bool) (skip bool, err error) {
149
+ return certmagic.NewACMEManager(m.magic, m.template).PreCheck(names, interactive)
150
+}
151
+
152
+// Issue obtains a certificate for the given csr.
153
+func (m *ACMEIssuer) Issue(ctx context.Context, csr *x509.CertificateRequest) (*certmagic.IssuedCertificate, error) {
154
+ return certmagic.NewACMEManager(m.magic, m.template).Issue(ctx, csr)
155
+}
156
+
157
+// IssuerKey returns the unique issuer key for the configured CA endpoint.
158
+func (m *ACMEIssuer) IssuerKey() string {
159
+ return m.template.IssuerKey() // does not need storage and cache
160
+}
161
+
162
+// Revoke revokes the given certificate.
163
+func (m *ACMEIssuer) Revoke(ctx context.Context, cert certmagic.CertificateResource) error {
164
+ return certmagic.NewACMEManager(m.magic, m.template).Revoke(ctx, cert)
165
+}
166
+
167
+// onDemandAskRequest makes a request to the ask URL
168
+// to see if a certificate can be obtained for name.
169
+// The certificate request should be denied if this
170
+// returns an error.
171
+func onDemandAskRequest(ask string, name string) error {
172
+ askURL, err := url.Parse(ask)
173
+ if err != nil {
174
+ return fmt.Errorf("parsing ask URL: %v", err)
175
+ }
176
+ qs := askURL.Query()
177
+ qs.Set("domain", name)
178
+ askURL.RawQuery = qs.Encode()
179
+
180
+ resp, err := onDemandAskClient.Get(askURL.String())
181
+ if err != nil {
182
+ return fmt.Errorf("error checking %v to deterine if certificate for hostname '%s' should be allowed: %v",
183
+ ask, name, err)
184
+ }
185
+ resp.Body.Close()
186
+
187
+ if resp.StatusCode < 200 || resp.StatusCode > 299 {
188
+ return fmt.Errorf("certificate for hostname '%s' not allowed; non-2xx status code %d returned from %v",
189
+ name, resp.StatusCode, ask)
190
+ }
191
+
192
+ return nil
193
+}
194
+
195
+// DNSProviderMaker is a type that can create a new DNS provider.
196
+// Modules in the tls.dns namespace should implement this interface.
197
+type DNSProviderMaker interface {
198
+ NewDNSProvider() (challenge.Provider, error)
199
+}
200
+
201
+// Interface guards
202
+var (
203
+ _ certmagic.Issuer = (*ACMEIssuer)(nil)
204
+ _ certmagic.Revoker = (*ACMEIssuer)(nil)
205
+ _ certmagic.PreChecker = (*ACMEIssuer)(nil)
206
+ _ ConfigSetter = (*ACMEIssuer)(nil)
207
+)
modules/caddytls/acmemanager.go
deleted
-252
@@ -1,252 +0,0 @@
1
-// Copyright 2015 Matthew Holt and The Caddy Authors
2
-//
3
-// Licensed under the Apache License, Version 2.0 (the "License");
4
-// you may not use this file except in compliance with the License.
5
-// You may obtain a copy of the License at
6
-//
7
-// http://www.apache.org/licenses/LICENSE-2.0
8
-//
9
-// Unless required by applicable law or agreed to in writing, software
10
-// distributed under the License is distributed on an "AS IS" BASIS,
11
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
-// See the License for the specific language governing permissions and
13
-// limitations under the License.
14
-
15
-package caddytls
16
-
17
-import (
18
- "crypto/x509"
19
- "encoding/json"
20
- "fmt"
21
- "io/ioutil"
22
- "net/url"
23
- "time"
24
-
25
- "github.com/caddyserver/caddy/v2"
26
- "github.com/go-acme/lego/v3/challenge"
27
- "github.com/mholt/certmagic"
28
-)
29
-
30
-func init() {
31
- caddy.RegisterModule(ACMEManagerMaker{})
32
-}
33
-
34
-// ACMEManagerMaker makes an ACME manager
35
-// for managing certificates using ACME.
36
-// If crafting one manually rather than
37
-// through the config-unmarshal process
38
-// (provisioning), be sure to call
39
-// SetDefaults to ensure sane defaults
40
-// after you have configured this struct
41
-// to your liking.
42
-type ACMEManagerMaker struct {
43
- // The URL to the CA's ACME directory endpoint.
44
- CA string `json:"ca,omitempty"`
45
-
46
- // Your email address, so the CA can contact you if necessary.
47
- // Not required, but strongly recommended to provide one so
48
- // you can be reached if there is a problem. Your email is
49
- // not sent to any Caddy mothership or used for any purpose
50
- // other than ACME transactions.
51
- Email string `json:"email,omitempty"`
52
-
53
- // How long before a certificate's expiration to try renewing it.
54
- // Should usually be about 1/3 of certificate lifetime, but long
55
- // enough to give yourself time to troubleshoot problems before
56
- // expiration. Default: 30d
57
- RenewAhead caddy.Duration `json:"renew_ahead,omitempty"`
58
-
59
- // The type of key to generate for the certificate.
60
- // Supported values: `rsa2048`, `rsa4096`, `p256`, `p384`.
61
- KeyType string `json:"key_type,omitempty"`
62
-
63
- // Time to wait before timing out an ACME operation.
64
- ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"`
65
-
66
- // If true, certificates will be requested with MustStaple. Not all
67
- // CAs support this, and there are potentially serious consequences
68
- // of enabling this feature without proper threat modeling.
69
- MustStaple bool `json:"must_staple,omitempty"`
70
-
71
- // Configures the various ACME challenge types.
72
- Challenges *ChallengesConfig `json:"challenges,omitempty"`
73
-
74
- // If true, certificates will be managed "on demand", that is, during
75
- // TLS handshakes or when needed, as opposed to at startup or config
76
- // load.
77
- OnDemand bool `json:"on_demand,omitempty"`
78
-
79
- // Optionally configure a separate storage module associated with this
80
- // manager, instead of using Caddy's global/default-configured storage.
81
- Storage json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
82
-
83
- // An array of files of CA certificates to accept when connecting to the
84
- // ACME CA. Generally, you should only use this if the ACME CA endpoint
85
- // is internal or for development/testing purposes.
86
- TrustedRootsPEMFiles []string `json:"trusted_roots_pem_files,omitempty"`
87
-
88
- storage certmagic.Storage
89
- rootPool *x509.CertPool
90
-}
91
-
92
-// CaddyModule returns the Caddy module information.
93
-func (ACMEManagerMaker) CaddyModule() caddy.ModuleInfo {
94
- return caddy.ModuleInfo{
95
- ID: "tls.management.acme",
96
- New: func() caddy.Module { return new(ACMEManagerMaker) },
97
- }
98
-}
99
-
100
-// NewManager is a no-op to satisfy the ManagerMaker interface,
101
-// because this manager type is a special case.
102
-func (m ACMEManagerMaker) NewManager(interactive bool) (certmagic.Manager, error) {
103
- return nil, nil
104
-}
105
-
106
-// Provision sets up m.
107
-func (m *ACMEManagerMaker) Provision(ctx caddy.Context) error {
108
- // DNS providers
109
- if m.Challenges != nil && m.Challenges.DNSRaw != nil {
110
- val, err := ctx.LoadModule(m.Challenges, "DNSRaw")
111
- if err != nil {
112
- return fmt.Errorf("loading DNS provider module: %v", err)
113
- }
114
- prov, err := val.(DNSProviderMaker).NewDNSProvider()
115
- if err != nil {
116
- return fmt.Errorf("making DNS provider: %v", err)
117
- }
118
- m.Challenges.DNS = prov
119
- }
120
-
121
- // policy-specific storage implementation
122
- if m.Storage != nil {
123
- val, err := ctx.LoadModule(m, "Storage")
124
- if err != nil {
125
- return fmt.Errorf("loading TLS storage module: %v", err)
126
- }
127
- cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()
128
- if err != nil {
129
- return fmt.Errorf("creating TLS storage configuration: %v", err)
130
- }
131
- m.storage = cmStorage
132
- }
133
-
134
- // add any custom CAs to trust store
135
- if len(m.TrustedRootsPEMFiles) > 0 {
136
- m.rootPool = x509.NewCertPool()
137
- for _, pemFile := range m.TrustedRootsPEMFiles {
138
- pemData, err := ioutil.ReadFile(pemFile)
139
- if err != nil {
140
- return fmt.Errorf("loading trusted root CA's PEM file: %s: %v", pemFile, err)
141
- }
142
- if !m.rootPool.AppendCertsFromPEM(pemData) {
143
- return fmt.Errorf("unable to add %s to trust pool: %v", pemFile, err)
144
- }
145
- }
146
- }
147
-
148
- return nil
149
-}
150
-
151
-// makeCertMagicConfig converts m into a certmagic.Config, because
152
-// this is a special case where the default manager is the certmagic
153
-// Config and not a separate manager.
154
-func (m *ACMEManagerMaker) makeCertMagicConfig(ctx caddy.Context) certmagic.Config {
155
- storage := m.storage
156
- if storage == nil {
157
- storage = ctx.Storage()
158
- }
159
-
160
- var ond *certmagic.OnDemandConfig
161
- if m.OnDemand {
162
- var onDemand *OnDemandConfig
163
- appVal, err := ctx.App("tls")
164
- if err == nil && appVal.(*TLS).Automation != nil {
165
- onDemand = appVal.(*TLS).Automation.OnDemand
166
- }
167
-
168
- ond = &certmagic.OnDemandConfig{
169
- DecisionFunc: func(name string) error {
170
- if onDemand != nil {
171
- if onDemand.Ask != "" {
172
- err := onDemandAskRequest(onDemand.Ask, name)
173
- if err != nil {
174
- return err
175
- }
176
- }
177
- // check the rate limiter last because
178
- // doing so makes a reservation
179
- if !onDemandRateLimiter.Allow() {
180
- return fmt.Errorf("on-demand rate limit exceeded")
181
- }
182
- }
183
- return nil
184
- },
185
- }
186
- }
187
-
188
- cfg := certmagic.Config{
189
- CA: m.CA,
190
- Email: m.Email,
191
- Agreed: true,
192
- RenewDurationBefore: time.Duration(m.RenewAhead),
193
- KeyType: supportedCertKeyTypes[m.KeyType],
194
- CertObtainTimeout: time.Duration(m.ACMETimeout),
195
- OnDemand: ond,
196
- MustStaple: m.MustStaple,
197
- Storage: storage,
198
- TrustedRoots: m.rootPool,
199
- // TODO: listenHost
200
- }
201
-
202
- if m.Challenges != nil {
203
- if m.Challenges.HTTP != nil {
204
- cfg.DisableHTTPChallenge = m.Challenges.HTTP.Disabled
205
- cfg.AltHTTPPort = m.Challenges.HTTP.AlternatePort
206
- }
207
- if m.Challenges.TLSALPN != nil {
208
- cfg.DisableTLSALPNChallenge = m.Challenges.TLSALPN.Disabled
209
- cfg.AltTLSALPNPort = m.Challenges.TLSALPN.AlternatePort
210
- }
211
- cfg.DNSProvider = m.Challenges.DNS
212
- }
213
-
214
- return cfg
215
-}
216
-
217
-// onDemandAskRequest makes a request to the ask URL
218
-// to see if a certificate can be obtained for name.
219
-// The certificate request should be denied if this
220
-// returns an error.
221
-func onDemandAskRequest(ask string, name string) error {
222
- askURL, err := url.Parse(ask)
223
- if err != nil {
224
- return fmt.Errorf("parsing ask URL: %v", err)
225
- }
226
- qs := askURL.Query()
227
- qs.Set("domain", name)
228
- askURL.RawQuery = qs.Encode()
229
-
230
- resp, err := onDemandAskClient.Get(askURL.String())
231
- if err != nil {
232
- return fmt.Errorf("error checking %v to deterine if certificate for hostname '%s' should be allowed: %v",
233
- ask, name, err)
234
- }
235
- resp.Body.Close()
236
-
237
- if resp.StatusCode < 200 || resp.StatusCode > 299 {
238
- return fmt.Errorf("certificate for hostname '%s' not allowed; non-2xx status code %d returned from %v",
239
- name, resp.StatusCode, ask)
240
- }
241
-
242
- return nil
243
-}
244
-
245
-// DNSProviderMaker is a type that can create a new DNS provider.
246
-// Modules in the tls.dns namespace should implement this interface.
247
-type DNSProviderMaker interface {
248
- NewDNSProvider() (challenge.Provider, error)
249
-}
250
-
251
-// Interface guard
252
-var _ ManagerMaker = (*ACMEManagerMaker)(nil)
modules/caddytls/certselection.go
+1
-1
@@ -7,7 +7,7 @@ import (
7
"math/big"
8
9
"github.com/caddyserver/caddy/v2"
10
- "github.com/mholt/certmagic"
10
+ "github.com/caddyserver/certmagic"
11
)
12
13
func init() {
modules/caddytls/connpolicy.go
+37
-23
@@ -23,8 +23,8 @@ import (
23
"strings"
24
25
"github.com/caddyserver/caddy/v2"
26
+ "github.com/caddyserver/certmagic"
27
"github.com/go-acme/lego/v3/challenge/tlsalpn01"
27
- "github.com/mholt/certmagic"
28
)
29
30
// ConnectionPolicies is an ordered group of connection policies;
@@ -32,16 +32,15 @@ import (
32
// connections at handshake-time.
33
type ConnectionPolicies []*ConnectionPolicy
34
35
-// TLSConfig converts the group of policies to a standard-lib-compatible
36
-// TLS configuration which selects the first matching policy based on
37
-// the ClientHello.
38
-func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) (*tls.Config, error) {
39
- // set up each of the connection policies
35
+// Provision sets up each connection policy. It should be called
36
+// during the Validate() phase, after the TLS app (if any) is
37
+// already set up.
38
+func (cp ConnectionPolicies) Provision(ctx caddy.Context) error {
39
for i, pol := range cp {
40
// matchers
41
mods, err := ctx.LoadModule(pol, "MatchersRaw")
42
if err != nil {
44
- return nil, fmt.Errorf("loading handshake matchers: %v", err)
43
+ return fmt.Errorf("loading handshake matchers: %v", err)
44
}
45
for _, modIface := range mods.(map[string]interface{}) {
46
cp[i].matchers = append(cp[i].matchers, modIface.(ConnectionMatcher))
@@ -51,20 +50,24 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) (*tls.Config, error) {
50
if pol.CertSelection != nil {
51
val, err := ctx.LoadModule(pol, "CertSelection")
52
if err != nil {
54
- return nil, fmt.Errorf("loading certificate selection module: %s", err)
53
+ return fmt.Errorf("loading certificate selection module: %s", err)
54
}
55
cp[i].certSelector = val.(certmagic.CertificateSelector)
56
}
58
- }
57
60
- // pre-build standard TLS configs so we don't have to at handshake-time
61
- for i := range cp {
62
- err := cp[i].buildStandardTLSConfig(ctx)
58
+ // pre-build standard TLS config so we don't have to at handshake-time
59
+ err = pol.buildStandardTLSConfig(ctx)
60
if err != nil {
64
- return nil, fmt.Errorf("connection policy %d: building standard TLS config: %s", i, err)
61
+ return fmt.Errorf("connection policy %d: building standard TLS config: %s", i, err)
62
}
63
}
64
65
+ return nil
66
+}
67
+
68
+// TLSConfig returns a standard-lib-compatible TLS configuration which
69
+// selects the first matching policy based on the ClientHello.
70
+func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) *tls.Config {
71
// using ServerName to match policies is extremely common, especially in configs
72
// with lots and lots of different policies; we can fast-track those by indexing
73
// them by SNI, so we don't have to iterate potentially thousands of policies
@@ -102,7 +105,7 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) (*tls.Config, error) {
105
106
return nil, fmt.Errorf("no server TLS configuration available for ClientHello: %+v", hello)
107
},
105
- }, nil
108
+ }
109
}
110
111
// ConnectionPolicy specifies the logic for handling a TLS handshake.
@@ -137,6 +140,10 @@ type ConnectionPolicy struct {
140
// Enables and configures TLS client authentication.
141
ClientAuthentication *ClientAuthentication `json:"client_authentication,omitempty"`
142
143
+ // DefaultSNI becomes the ServerName in a ClientHello if there
144
+ // is no policy configured for the empty SNI value.
145
+ DefaultSNI string `json:"default_sni,omitempty"`
146
+
147
matchers []ConnectionMatcher
148
certSelector certmagic.CertificateSelector
149
@@ -158,15 +165,24 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
165
NextProtos: p.ALPN,
166
PreferServerCipherSuites: true,
167
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
161
- cfgTpl, err := tlsApp.getConfigForName(hello.ServerName)
162
- if err != nil {
163
- return nil, fmt.Errorf("getting config for name %s: %v", hello.ServerName, err)
164
- }
165
- newCfg := certmagic.New(tlsApp.certCache, cfgTpl)
168
+ // TODO: I don't love how this works: we pre-build certmagic configs
169
+ // so that handshakes are faster. Unfortunately, certmagic configs are
170
+ // comprised of settings from both a TLS connection policy and a TLS
171
+ // automation policy. The only two fields (as of March 2020; v2 beta 16)
172
+ // of a certmagic config that come from the TLS connection policy are
173
+ // CertSelection and DefaultServerName, so an automation policy is what
174
+ // builds the base certmagic config. Since the pre-built config is
175
+ // shared, I don't think we can change any of its fields per-handshake,
176
+ // hence the awkward shallow copy (dereference) here and the subsequent
177
+ // changing of some of its fields. I'm worried this dereference allocates
178
+ // more at handshake-time, but I don't know how to practically pre-build
179
+ // a certmagic config for each combination of conn policy + automation policy...
180
+ cfg := *tlsApp.getConfigForName(hello.ServerName)
181
if p.certSelector != nil {
167
- newCfg.CertSelection = p.certSelector
182
+ cfg.CertSelection = p.certSelector
183
}
169
- return newCfg.GetCertificate(hello)
184
+ cfg.DefaultServerName = p.DefaultSNI
185
+ return cfg.GetCertificate(hello)
186
},
187
MinVersion: tls.VersionTLS12,
188
MaxVersion: tls.VersionTLS13,
@@ -240,8 +256,6 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
256
}
257
}
258
243
- // TODO: other fields
244
-
259
setDefaultTLSParams(cfg)
260
261
p.stdTLSConfig = cfg
modules/caddytls/distributedstek/distributedstek.go
+1
-1
@@ -32,7 +32,7 @@ import (
32
33
"github.com/caddyserver/caddy/v2"
34
"github.com/caddyserver/caddy/v2/modules/caddytls"
35
- "github.com/mholt/certmagic"
35
+ "github.com/caddyserver/certmagic"
36
)
37
38
func init() {
modules/caddytls/tls.go
+189
-59
@@ -23,8 +23,8 @@ import (
23
"time"
24
25
"github.com/caddyserver/caddy/v2"
26
+ "github.com/caddyserver/certmagic"
27
"github.com/go-acme/lego/v3/challenge"
27
- "github.com/mholt/certmagic"
28
"go.uber.org/zap"
29
)
30
@@ -71,13 +71,15 @@ func (TLS) CaddyModule() caddy.ModuleInfo {
71
72
// Provision sets up the configuration for the TLS app.
73
func (t *TLS) Provision(ctx caddy.Context) error {
74
+ // TODO: Move assets to the new folder structure!!
75
+
76
t.ctx = ctx
77
t.logger = ctx.Logger(t)
78
79
// set up a new certificate cache; this (re)loads all certificates
80
cacheOpts := certmagic.CacheOptions{
79
- GetConfigForCert: func(cert certmagic.Certificate) (certmagic.Config, error) {
80
- return t.getConfigForName(cert.Names[0])
81
+ GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
82
+ return t.getConfigForName(cert.Names[0]), nil
83
},
84
}
85
if t.Automation != nil {
@@ -87,20 +89,25 @@ func (t *TLS) Provision(ctx caddy.Context) error {
89
t.certCache = certmagic.NewCache(cacheOpts)
90
91
// automation/management policies
90
- if t.Automation != nil {
91
- for i, ap := range t.Automation.Policies {
92
- val, err := ctx.LoadModule(ap, "ManagementRaw")
93
- if err != nil {
94
- return fmt.Errorf("loading TLS automation management module: %s", err)
95
- }
96
- t.Automation.Policies[i].Management = val.(ManagerMaker)
92
+ if t.Automation == nil {
93
+ t.Automation = new(AutomationConfig)
94
+ }
95
+ t.Automation.defaultAutomationPolicy = new(AutomationPolicy)
96
+ err := t.Automation.defaultAutomationPolicy.provision(t)
97
+ if err != nil {
98
+ return fmt.Errorf("provisioning default automation policy: %v", err)
99
+ }
100
+ for i, ap := range t.Automation.Policies {
101
+ err := ap.provision(t)
102
+ if err != nil {
103
+ return fmt.Errorf("provisioning automation policy %d: %v", i, err)
104
}
105
}
106
107
// certificate loaders
108
val, err := ctx.LoadModule(t, "CertificatesRaw")
109
if err != nil {
103
- return fmt.Errorf("loading TLS automation management module: %s", err)
110
+ return fmt.Errorf("loading certificate loader modules: %s", err)
111
}
112
for modName, modIface := range val.(map[string]interface{}) {
113
if modName == "automate" {
@@ -216,12 +223,11 @@ func (t *TLS) Manage(names []string) error {
223
// certmagic.Config for each (potentially large) group of names
224
// and call ManageSync/ManageAsync just once for the whole batch
225
for ap, names := range policyToNames {
219
- magic := certmagic.New(t.certCache, ap.makeCertMagicConfig(t.ctx))
226
var err error
227
if ap.ManageSync {
222
- err = magic.ManageSync(names)
228
+ err = ap.magic.ManageSync(names)
229
} else {
224
- err = magic.ManageAsync(t.ctx.Context, names)
230
+ err = ap.magic.ManageAsync(t.ctx.Context, names)
231
}
232
if err != nil {
233
return fmt.Errorf("automate: manage %v: %v", names, err)
@@ -232,36 +238,54 @@ func (t *TLS) Manage(names []string) error {
238
}
239
240
// HandleHTTPChallenge ensures that the HTTP challenge is handled for the
235
-// certificate named by r.Host, if it is an HTTP challenge request.
241
+// certificate named by r.Host, if it is an HTTP challenge request. It
242
+// requires that the automation policy for r.Host has an issue of type
243
+// *certmagic.ACMEManager.
244
func (t *TLS) HandleHTTPChallenge(w http.ResponseWriter, r *http.Request) bool {
245
if !certmagic.LooksLikeHTTPChallenge(r) {
246
return false
247
}
248
ap := t.getAutomationPolicyForName(r.Host)
241
- magic := certmagic.New(t.certCache, ap.makeCertMagicConfig(t.ctx))
242
- return magic.HandleHTTPChallenge(w, r)
249
+ if ap.magic.Issuer == nil {
250
+ return false
251
+ }
252
+ if am, ok := ap.magic.Issuer.(*certmagic.ACMEManager); ok {
253
+ return am.HandleHTTPChallenge(w, r)
254
+ }
255
+ return false
256
+}
257
+
258
+// AddAutomationPolicy provisions and adds ap to the list of the app's
259
+// automation policies.
260
+func (t *TLS) AddAutomationPolicy(ap *AutomationPolicy) error {
261
+ if t.Automation == nil {
262
+ t.Automation = new(AutomationConfig)
263
+ }
264
+ err := ap.provision(t)
265
+ if err != nil {
266
+ return err
267
+ }
268
+ t.Automation.Policies = append(t.Automation.Policies, ap)
269
+ return nil
270
}
271
245
-func (t *TLS) getConfigForName(name string) (certmagic.Config, error) {
272
+func (t *TLS) getConfigForName(name string) *certmagic.Config {
273
ap := t.getAutomationPolicyForName(name)
247
- return ap.makeCertMagicConfig(t.ctx), nil
274
+ return ap.magic
275
}
276
277
func (t *TLS) getAutomationPolicyForName(name string) *AutomationPolicy {
251
- if t.Automation != nil {
252
- for _, ap := range t.Automation.Policies {
253
- if len(ap.Hosts) == 0 {
254
- // no host filter is an automatic match
278
+ for _, ap := range t.Automation.Policies {
279
+ if len(ap.Hosts) == 0 {
280
+ return ap // no host filter is an automatic match
281
+ }
282
+ for _, h := range ap.Hosts {
283
+ if h == name {
284
return ap
285
}
257
- for _, h := range ap.Hosts {
258
- if h == name {
259
- return ap
260
- }
261
- }
286
}
287
}
264
- return defaultAutomationPolicy
288
+ return t.Automation.defaultAutomationPolicy
289
}
290
291
// AllMatchingCertificates returns the list of all certificates in
@@ -309,10 +333,8 @@ func (t *TLS) cleanStorageUnits() {
333
// then clean each storage defined in ACME automation policies
334
if t.Automation != nil {
335
for _, ap := range t.Automation.Policies {
312
- if acmeMgmt, ok := ap.Management.(ACMEManagerMaker); ok {
313
- if acmeMgmt.storage != nil {
314
- certmagic.CleanStorage(acmeMgmt.storage, options)
315
- }
336
+ if ap.storage != nil {
337
+ certmagic.CleanStorage(ap.storage, options)
338
}
339
}
340
}
@@ -355,23 +377,56 @@ type AutomationConfig struct {
377
OCSPCheckInterval caddy.Duration `json:"ocsp_interval,omitempty"`
378
379
// Every so often, Caddy will scan all loaded, managed
358
- // certificates for expiration. Certificates which are
359
- // about 2/3 into their valid lifetime are due for
360
- // renewal. This setting changes how frequently the scan
361
- // is performed. If your certificate lifetimes are very
362
- // short (less than ~1 week), you should customize this.
380
+ // certificates for expiration. This setting changes how
381
+ // frequently the scan for expiring certificates is
382
+ // performed. If your certificate lifetimes are very
383
+ // short (less than ~24 hours), you should set this to
384
+ // a low value.
385
RenewCheckInterval caddy.Duration `json:"renew_interval,omitempty"`
386
+
387
+ defaultAutomationPolicy *AutomationPolicy
388
}
389
390
// AutomationPolicy designates the policy for automating the
391
// management (obtaining, renewal, and revocation) of managed
392
// TLS certificates.
393
+//
394
+// An AutomationPolicy value is not valid until it has been
395
+// provisioned; use the `AddAutomationPolicy()` method on the
396
+// TLS app to properly provision a new policy.
397
type AutomationPolicy struct {
398
// Which hostnames this policy applies to.
399
Hosts []string `json:"hosts,omitempty"`
400
373
- // How to manage certificates.
374
- ManagementRaw json.RawMessage `json:"management,omitempty" caddy:"namespace=tls.management inline_key=module"`
401
+ // The module that will issue certificates. Default: acme
402
+ IssuerRaw json.RawMessage `json:"issuer,omitempty" caddy:"namespace=tls.issuance inline_key=module"`
403
+
404
+ // If true, certificates will be requested with MustStaple. Not all
405
+ // CAs support this, and there are potentially serious consequences
406
+ // of enabling this feature without proper threat modeling.
407
+ MustStaple bool `json:"must_staple,omitempty"`
408
+
409
+ // How long before a certificate's expiration to try renewing it,
410
+ // as a function of its total lifetime. As a general and conservative
411
+ // rule, it is a good idea to renew a certificate when it has about
412
+ // 1/3 of its total lifetime remaining. This utilizes the majority
413
+ // of the certificate's lifetime while still saving time to
414
+ // troubleshoot problems. However, for extremely short-lived certs,
415
+ // you may wish to increase the ratio to ~1/2.
416
+ RenewalWindowRatio float64 `json:"renewal_window_ratio,omitempty"`
417
+
418
+ // The type of key to generate for certificates.
419
+ // Supported values: `ed25519`, `p256`, `p384`, `rsa2048`, `rsa4096`.
420
+ KeyType string `json:"key_type,omitempty"`
421
+
422
+ // Optionally configure a separate storage module associated with this
423
+ // manager, instead of using Caddy's global/default-configured storage.
424
+ StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
425
+
426
+ // If true, certificates will be managed "on demand", that is, during
427
+ // TLS handshakes or when needed, as opposed to at startup or config
428
+ // load.
429
+ OnDemand bool `json:"on_demand,omitempty"`
430
431
// If true, certificate management will be conducted
432
// in the foreground; this will block config reloads
@@ -381,23 +436,96 @@ type AutomationPolicy struct {
436
// of your control. Default: false
437
ManageSync bool `json:"manage_sync,omitempty"`
438
384
- Management ManagerMaker `json:"-"`
439
+ Issuer certmagic.Issuer `json:"-"`
440
+
441
+ magic *certmagic.Config
442
+ storage certmagic.Storage
443
}
444
387
-// makeCertMagicConfig converts ap into a CertMagic config. Passing onDemand
388
-// is necessary because the automation policy does not have convenient access
389
-// to the TLS app's global on-demand policies;
390
-func (ap AutomationPolicy) makeCertMagicConfig(ctx caddy.Context) certmagic.Config {
391
- // default manager (ACME) is a special case because of how CertMagic is designed
392
- // TODO: refactor certmagic so that ACME manager is not a special case by extracting
393
- // its config fields out of the certmagic.Config struct, or something...
394
- if acmeMgmt, ok := ap.Management.(*ACMEManagerMaker); ok {
395
- return acmeMgmt.makeCertMagicConfig(ctx)
445
+// provision converts ap into a CertMagic config.
446
+func (ap *AutomationPolicy) provision(tlsApp *TLS) error {
447
+ // policy-specific storage implementation
448
+ if ap.StorageRaw != nil {
449
+ val, err := tlsApp.ctx.LoadModule(ap, "StorageRaw")
450
+ if err != nil {
451
+ return fmt.Errorf("loading TLS storage module: %v", err)
452
+ }
453
+ cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()
454
+ if err != nil {
455
+ return fmt.Errorf("creating TLS storage configuration: %v", err)
456
+ }
457
+ ap.storage = cmStorage
458
+ }
459
+
460
+ var ond *certmagic.OnDemandConfig
461
+ if ap.OnDemand {
462
+ var onDemand *OnDemandConfig
463
+ if tlsApp.Automation != nil {
464
+ onDemand = tlsApp.Automation.OnDemand
465
+ }
466
+
467
+ ond = &certmagic.OnDemandConfig{
468
+ DecisionFunc: func(name string) error {
469
+ if onDemand != nil {
470
+ if onDemand.Ask != "" {
471
+ err := onDemandAskRequest(onDemand.Ask, name)
472
+ if err != nil {
473
+ return err
474
+ }
475
+ }
476
+ // check the rate limiter last because
477
+ // doing so makes a reservation
478
+ if !onDemandRateLimiter.Allow() {
479
+ return fmt.Errorf("on-demand rate limit exceeded")
480
+ }
481
+ }
482
+ return nil
483
+ },
484
+ }
485
+ }
486
+
487
+ keySource := certmagic.StandardKeyGenerator{
488
+ KeyType: supportedCertKeyTypes[ap.KeyType],
489
+ }
490
+
491
+ storage := ap.storage
492
+ if storage == nil {
493
+ storage = tlsApp.ctx.Storage()
494
}
495
398
- return certmagic.Config{
399
- NewManager: ap.Management.NewManager,
496
+ template := certmagic.Config{
497
+ MustStaple: ap.MustStaple,
498
+ RenewalWindowRatio: ap.RenewalWindowRatio,
499
+ KeySource: keySource,
500
+ OnDemand: ond,
501
+ Storage: storage,
502
}
503
+ cfg := certmagic.New(tlsApp.certCache, template)
504
+ ap.magic = cfg
505
+
506
+ if ap.IssuerRaw != nil {
507
+ val, err := tlsApp.ctx.LoadModule(ap, "IssuerRaw")
508
+ if err != nil {
509
+ return fmt.Errorf("loading TLS automation management module: %s", err)
510
+ }
511
+ ap.Issuer = val.(certmagic.Issuer)
512
+ }
513
+
514
+ // sometimes issuers may need the parent certmagic.Config in
515
+ // order to function properly (for example, ACMEIssuer needs
516
+ // access to the correct storage and cache so it can solve
517
+ // ACME challenges -- it's an annoying, inelegant circular
518
+ // dependency that I don't know how to resolve nicely!)
519
+ if configger, ok := ap.Issuer.(ConfigSetter); ok {
520
+ configger.SetConfig(cfg)
521
+ }
522
+
523
+ cfg.Issuer = ap.Issuer
524
+ if rev, ok := ap.Issuer.(certmagic.Revoker); ok {
525
+ cfg.Revoker = rev
526
+ }
527
+
528
+ return nil
529
}
530
531
// ChallengesConfig configures the ACME challenges.
@@ -482,11 +610,6 @@ type RateLimit struct {
610
Burst int `json:"burst,omitempty"`
611
}
612
485
-// ManagerMaker makes a certificate manager.
486
-type ManagerMaker interface {
487
- NewManager(interactive bool) (certmagic.Manager, error)
488
-}
489
-
613
// AutomateLoader is a no-op certificate loader module
614
// that is treated as a special case: it uses this app's
615
// automation features to load certificates for the
@@ -502,6 +625,15 @@ func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
625
}
626
}
627
628
+// ConfigSetter is implemented by certmagic.Issuers that
629
+// need access to a parent certmagic.Config as part of
630
+// their provisioning phase. For example, the ACMEIssuer
631
+// requires a config so it can access storage and the
632
+// cache to solve ACME challenges.
633
+type ConfigSetter interface {
634
+ SetConfig(cfg *certmagic.Config)
635
+}
636
+
637
// These perpetual values are used for on-demand TLS.
638
var (
639
onDemandRateLimiter = certmagic.NewRateLimiter(0, 0)
@@ -521,8 +653,6 @@ var (
653
storageCleanMu sync.Mutex
654
)
655
524
-var defaultAutomationPolicy = &AutomationPolicy{Management: new(ACMEManagerMaker)}
525
-
656
// Interface guards
657
var (
658
_ caddy.App = (*TLS)(nil)
modules/caddytls/values.go
+35
-6
@@ -17,8 +17,9 @@ package caddytls
17
import (
18
"crypto/tls"
19
"crypto/x509"
20
+ "fmt"
21
21
- "github.com/go-acme/lego/v3/certcrypto"
22
+ "github.com/caddyserver/certmagic"
23
"github.com/klauspost/cpuid"
24
)
25
@@ -101,11 +102,12 @@ var SupportedCurves = map[string]tls.CurveID{
102
103
// supportedCertKeyTypes is all the key types that are supported
104
// for certificates that are obtained through ACME.
104
-var supportedCertKeyTypes = map[string]certcrypto.KeyType{
105
- "rsa_2048": certcrypto.RSA2048,
106
- "rsa_4096": certcrypto.RSA4096,
107
- "ec_p256": certcrypto.EC256,
108
- "ec_p384": certcrypto.EC384,
105
+var supportedCertKeyTypes = map[string]certmagic.KeyType{
106
+ "rsa2048": certmagic.RSA2048,
107
+ "rsa4096": certmagic.RSA4096,
108
+ "p256": certmagic.P256,
109
+ "p384": certmagic.P384,
110
+ "ed25519": certmagic.ED25519,
111
}
112
113
// defaultCurves is the list of only the curves we want to use
@@ -127,9 +129,36 @@ var SupportedProtocols = map[string]uint16{
129
"tls1.3": tls.VersionTLS13,
130
}
131
132
+// unsupportedProtocols is a map of unsupported protocols.
133
+// Used for logging only, not enforcement.
134
+var unsupportedProtocols = map[string]uint16{
135
+ "ssl3.0": tls.VersionSSL30,
136
+ "tls1.0": tls.VersionTLS10,
137
+ "tls1.1": tls.VersionTLS11,
138
+}
139
+
140
// publicKeyAlgorithms is the map of supported public key algorithms.
141
var publicKeyAlgorithms = map[string]x509.PublicKeyAlgorithm{
142
"rsa": x509.RSA,
143
"dsa": x509.DSA,
144
"ecdsa": x509.ECDSA,
145
}
146
+
147
+// ProtocolName returns the standard name for the passed protocol version ID
148
+// (e.g. "TLS1.3") or a fallback representation of the ID value if the version
149
+// is not supported.
150
+func ProtocolName(id uint16) string {
151
+ for k, v := range SupportedProtocols {
152
+ if v == id {
153
+ return k
154
+ }
155
+ }
156
+
157
+ for k, v := range unsupportedProtocols {
158
+ if v == id {
159
+ return k
160
+ }
161
+ }
162
+
163
+ return fmt.Sprintf("0x%04x", id)
164
+}
modules/filestorage/filestorage.go
+1
-1
@@ -17,7 +17,7 @@ package filestorage
17
import (
18
"github.com/caddyserver/caddy/v2"
19
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
20
- "github.com/mholt/certmagic"
20
+ "github.com/caddyserver/certmagic"
21
)
22
23
func init() {
modules/logging/encoders.go
+143
-12
@@ -21,6 +21,7 @@ import (
21
"time"
22
23
"github.com/caddyserver/caddy/v2"
24
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
25
zaplogfmt "github.com/jsternberg/zap-logfmt"
26
"go.uber.org/zap"
27
"go.uber.org/zap/buffer"
@@ -31,7 +32,7 @@ func init() {
32
caddy.RegisterModule(ConsoleEncoder{})
33
caddy.RegisterModule(JSONEncoder{})
34
caddy.RegisterModule(LogfmtEncoder{})
34
- caddy.RegisterModule(StringEncoder{})
35
+ caddy.RegisterModule(SingleFieldEncoder{})
36
}
37
38
// ConsoleEncoder encodes log entries that are mostly human-readable.
@@ -54,6 +55,27 @@ func (ce *ConsoleEncoder) Provision(_ caddy.Context) error {
55
return nil
56
}
57
58
+// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
59
+//
60
+// console {
61
+// <common encoder config subdirectives...>
62
+// }
63
+//
64
+// See the godoc on the LogEncoderConfig type for the syntax of
65
+// subdirectives that are common to most/all encoders.
66
+func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
67
+ for d.Next() {
68
+ if d.NextArg() {
69
+ return d.ArgErr()
70
+ }
71
+ err := ce.LogEncoderConfig.UnmarshalCaddyfile(d)
72
+ if err != nil {
73
+ return err
74
+ }
75
+ }
76
+ return nil
77
+}
78
+
79
// JSONEncoder encodes entries as JSON.
80
type JSONEncoder struct {
81
zapcore.Encoder `json:"-"`
@@ -74,6 +96,27 @@ func (je *JSONEncoder) Provision(_ caddy.Context) error {
96
return nil
97
}
98
99
+// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
100
+//
101
+// json {
102
+// <common encoder config subdirectives...>
103
+// }
104
+//
105
+// See the godoc on the LogEncoderConfig type for the syntax of
106
+// subdirectives that are common to most/all encoders.
107
+func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
108
+ for d.Next() {
109
+ if d.NextArg() {
110
+ return d.ArgErr()
111
+ }
112
+ err := je.LogEncoderConfig.UnmarshalCaddyfile(d)
113
+ if err != nil {
114
+ return err
115
+ }
116
+ }
117
+ return nil
118
+}
119
+
120
// LogfmtEncoder encodes log entries as logfmt:
121
// https://www.brandur.org/logfmt
122
type LogfmtEncoder struct {
@@ -95,26 +138,47 @@ func (lfe *LogfmtEncoder) Provision(_ caddy.Context) error {
138
return nil
139
}
140
98
-// StringEncoder writes a log entry that consists entirely
141
+// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
142
+//
143
+// logfmt {
144
+// <common encoder config subdirectives...>
145
+// }
146
+//
147
+// See the godoc on the LogEncoderConfig type for the syntax of
148
+// subdirectives that are common to most/all encoders.
149
+func (lfe *LogfmtEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
150
+ for d.Next() {
151
+ if d.NextArg() {
152
+ return d.ArgErr()
153
+ }
154
+ err := lfe.LogEncoderConfig.UnmarshalCaddyfile(d)
155
+ if err != nil {
156
+ return err
157
+ }
158
+ }
159
+ return nil
160
+}
161
+
162
+// SingleFieldEncoder writes a log entry that consists entirely
163
// of a single string field in the log entry. This is useful
164
// for custom, self-encoded log entries that consist of a
165
// single field in the structured log entry.
102
-type StringEncoder struct {
166
+type SingleFieldEncoder struct {
167
zapcore.Encoder `json:"-"`
168
FieldName string `json:"field,omitempty"`
169
FallbackRaw json.RawMessage `json:"fallback,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
170
}
171
172
// CaddyModule returns the Caddy module information.
109
-func (StringEncoder) CaddyModule() caddy.ModuleInfo {
173
+func (SingleFieldEncoder) CaddyModule() caddy.ModuleInfo {
174
return caddy.ModuleInfo{
111
- ID: "caddy.logging.encoders.string",
112
- New: func() caddy.Module { return new(StringEncoder) },
175
+ ID: "caddy.logging.encoders.single_field",
176
+ New: func() caddy.Module { return new(SingleFieldEncoder) },
177
}
178
}
179
180
// Provision sets up the encoder.
117
-func (se *StringEncoder) Provision(ctx caddy.Context) error {
181
+func (se *SingleFieldEncoder) Provision(ctx caddy.Context) error {
182
if se.FallbackRaw != nil {
183
val, err := ctx.LoadModule(se, "FallbackRaw")
184
if err != nil {
@@ -132,16 +196,16 @@ func (se *StringEncoder) Provision(ctx caddy.Context) error {
196
// necessary because we implement our own EncodeEntry,
197
// and if we simply let the embedded encoder's Clone
198
// be promoted, it would return a clone of that, and
135
-// we'd lose our StringEncoder's EncodeEntry.
136
-func (se StringEncoder) Clone() zapcore.Encoder {
137
- return StringEncoder{
199
+// we'd lose our SingleFieldEncoder's EncodeEntry.
200
+func (se SingleFieldEncoder) Clone() zapcore.Encoder {
201
+ return SingleFieldEncoder{
202
Encoder: se.Encoder.Clone(),
203
FieldName: se.FieldName,
204
}
205
}
206
207
// EncodeEntry partially implements the zapcore.Encoder interface.
144
-func (se StringEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
208
+func (se SingleFieldEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
209
for _, f := range fields {
210
if f.Key == se.FieldName {
211
buf := bufferpool.Get()
@@ -158,6 +222,21 @@ func (se StringEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (
222
return se.Encoder.EncodeEntry(ent, fields)
223
}
224
225
+// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
226
+//
227
+// single_field <field_name>
228
+//
229
+func (se *SingleFieldEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
230
+ for d.Next() {
231
+ var fieldName string
232
+ if !d.AllArgs(&fieldName) {
233
+ return d.ArgErr()
234
+ }
235
+ se.FieldName = d.Val()
236
+ }
237
+ return nil
238
+}
239
+
240
// LogEncoderConfig holds configuration common to most encoders.
241
type LogEncoderConfig struct {
242
MessageKey *string `json:"message_key,omitempty"`
@@ -172,6 +251,53 @@ type LogEncoderConfig struct {
251
LevelFormat string `json:"level_format,omitempty"`
252
}
253
254
+// UnmarshalCaddyfile populates the struct from Caddyfile tokens. Syntax:
255
+//
256
+// {
257
+// message_key <key>
258
+// level_key <key>
259
+// time_key <key>
260
+// name_key <key>
261
+// caller_key <key>
262
+// stacktrace_key <key>
263
+// line_ending <char>
264
+// time_format <format>
265
+// level_format <format>
266
+// }
267
+//
268
+func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
269
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
270
+ subdir := d.Val()
271
+ var arg string
272
+ if !d.AllArgs(&arg) {
273
+ return d.ArgErr()
274
+ }
275
+ switch subdir {
276
+ case "message_key":
277
+ lec.MessageKey = &arg
278
+ case "level_key":
279
+ lec.LevelKey = &arg
280
+ case "time_key":
281
+ lec.TimeKey = &arg
282
+ case "name_key":
283
+ lec.NameKey = &arg
284
+ case "caller_key":
285
+ lec.CallerKey = &arg
286
+ case "stacktrace_key":
287
+ lec.StacktraceKey = &arg
288
+ case "line_ending":
289
+ lec.LineEnding = &arg
290
+ case "time_format":
291
+ lec.TimeFormat = arg
292
+ case "level_format":
293
+ lec.LevelFormat = arg
294
+ default:
295
+ return d.Errf("unrecognized subdirective %s", subdir)
296
+ }
297
+ }
298
+ return nil
299
+}
300
+
301
// ZapcoreEncoderConfig returns the equivalent zapcore.EncoderConfig.
302
// If lec is nil, zap.NewProductionEncoderConfig() is returned.
303
func (lec *LogEncoderConfig) ZapcoreEncoderConfig() zapcore.EncoderConfig {
@@ -263,5 +389,10 @@ var (
389
_ zapcore.Encoder = (*ConsoleEncoder)(nil)
390
_ zapcore.Encoder = (*JSONEncoder)(nil)
391
_ zapcore.Encoder = (*LogfmtEncoder)(nil)
266
- _ zapcore.Encoder = (*StringEncoder)(nil)
392
+ _ zapcore.Encoder = (*SingleFieldEncoder)(nil)
393
+
394
+ _ caddyfile.Unmarshaler = (*ConsoleEncoder)(nil)
395
+ _ caddyfile.Unmarshaler = (*JSONEncoder)(nil)
396
+ _ caddyfile.Unmarshaler = (*LogfmtEncoder)(nil)
397
+ _ caddyfile.Unmarshaler = (*SingleFieldEncoder)(nil)
398
)
modules/logging/filewriter.go
+75
-1
@@ -19,8 +19,12 @@ import (
19
"io"
20
"os"
21
"path/filepath"
22
+ "strconv"
23
+ "time"
24
25
"github.com/caddyserver/caddy/v2"
26
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
27
+ "github.com/dustin/go-humanize"
28
"gopkg.in/natefinch/lumberjack.v2"
29
)
30
@@ -125,7 +129,77 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
129
return os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
130
}
131
132
+// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
133
+//
134
+// file <filename> {
135
+// roll_disabled
136
+// roll_size <size>
137
+// roll_keep <num>
138
+// roll_keep_for <days>
139
+// }
140
+//
141
+// The roll_size value will be rounded down to number of megabytes (MiB).
142
+// The roll_keep_for duration will be rounded down to number of days.
143
+func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
144
+ for d.Next() {
145
+ if !d.NextArg() {
146
+ return d.ArgErr()
147
+ }
148
+ fw.Filename = d.Val()
149
+ if d.NextArg() {
150
+ return d.ArgErr()
151
+ }
152
+
153
+ for d.NextBlock(0) {
154
+ switch d.Val() {
155
+ case "roll_disabled":
156
+ var f bool
157
+ fw.Roll = &f
158
+ if d.NextArg() {
159
+ return d.ArgErr()
160
+ }
161
+
162
+ case "roll_size":
163
+ var sizeStr string
164
+ if !d.AllArgs(&sizeStr) {
165
+ return d.ArgErr()
166
+ }
167
+ size, err := humanize.ParseBytes(sizeStr)
168
+ if err != nil {
169
+ return d.Errf("parsing size: %v", err)
170
+ }
171
+ fw.RollSizeMB = int(size) / 1024 / 1024
172
+
173
+ case "roll_keep":
174
+ var keepStr string
175
+ if !d.AllArgs(&keepStr) {
176
+ return d.ArgErr()
177
+ }
178
+ keep, err := strconv.Atoi(keepStr)
179
+ if err != nil {
180
+ return d.Errf("parsing roll_keep number: %v", err)
181
+ }
182
+ fw.RollKeep = keep
183
+
184
+ case "roll_keep_for":
185
+ var keepForStr string
186
+ if !d.AllArgs(&keepForStr) {
187
+ return d.ArgErr()
188
+ }
189
+ keepFor, err := time.ParseDuration(keepForStr)
190
+ if err != nil {
191
+ return d.Errf("parsing roll_keep_for duration: %v", err)
192
+ }
193
+ fw.RollKeepDays = int(keepFor.Hours()) / 24
194
+ }
195
+ }
196
+ }
197
+ return nil
198
+}
199
+
200
// Interface guards
201
var (
130
- _ caddy.Provisioner = (*FileWriter)(nil)
202
+ _ caddy.Provisioner = (*FileWriter)(nil)
203
+ _ caddy.WriterOpener = (*FileWriter)(nil)
204
+ _ caddyfile.Unmarshaler = (*FileWriter)(nil)
205
)
modules/logging/netwriter.go
+21
-2
@@ -20,6 +20,7 @@ import (
20
"net"
21
22
"github.com/caddyserver/caddy/v2"
23
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
24
)
25
26
func init() {
@@ -75,8 +76,26 @@ func (nw NetWriter) OpenWriter() (io.WriteCloser, error) {
76
return net.Dial(nw.addr.Network, nw.addr.JoinHostPort(0))
77
}
78
79
+// UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
80
+//
81
+// net <address>
82
+//
83
+func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
84
+ for d.Next() {
85
+ if !d.NextArg() {
86
+ return d.ArgErr()
87
+ }
88
+ nw.Address = d.Val()
89
+ if d.NextArg() {
90
+ return d.ArgErr()
91
+ }
92
+ }
93
+ return nil
94
+}
95
+
96
// Interface guards
97
var (
80
- _ caddy.Provisioner = (*NetWriter)(nil)
81
- _ caddy.WriterOpener = (*NetWriter)(nil)
98
+ _ caddy.Provisioner = (*NetWriter)(nil)
99
+ _ caddy.WriterOpener = (*NetWriter)(nil)
100
+ _ caddyfile.Unmarshaler = (*NetWriter)(nil)
101
)
replacer.go
+4
-5
@@ -148,11 +148,10 @@ func (r *Replacer) replace(input, empty string,
148
if errOnUnknown {
149
return "", fmt.Errorf("unrecognized placeholder %s%s%s",
150
string(phOpen), key, string(phClose))
151
- } else if treatUnknownAsEmpty {
152
- if empty != "" {
153
- sb.WriteString(empty)
154
- }
155
- } else {
151
+ } else if !treatUnknownAsEmpty {
152
+ // if treatUnknownAsEmpty is true, we'll
153
+ // handle an empty val later; so only
154
+ // continue otherwise
155
lastWriteCursor = i
156
continue
157
}
replacer_test.go
+5
@@ -67,6 +67,11 @@ func TestReplacer(t *testing.T) {
67
input: `{{}`,
68
expect: "",
69
},
70
+ {
71
+ input: `{unknown}`,
72
+ empty: "-",
73
+ expect: "-",
74
+ },
75
} {
76
actual := rep.ReplaceAll(tc.input, tc.empty)
77
if actual != tc.expect {
sigtrap_posix.go
+1
-1
@@ -21,7 +21,7 @@ import (
21
"os/signal"
22
"syscall"
23
24
- "github.com/mholt/certmagic"
24
+ "github.com/caddyserver/certmagic"
25
"go.uber.org/zap"
26
)
27
storage.go
+1
-1
@@ -19,7 +19,7 @@ import (
19
"path/filepath"
20
"runtime"
21
22
- "github.com/mholt/certmagic"
22
+ "github.com/caddyserver/certmagic"
23
"go.uber.org/zap"
24
)
25