mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 13:43:47 +03:00
httpcaddyfile: Add acme_ca and email global options
Also add ability to access options from individual unmarshalers through the Helper values
This commit is contained in:
parent
7b4aa108c7
commit
1e66226217
5 changed files with 112 additions and 70 deletions
|
@ -86,6 +86,14 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
|||
var mgr caddytls.ACMEManagerMaker
|
||||
var off bool
|
||||
|
||||
// fill in global defaults, if configured
|
||||
if email := h.Option("email"); email != nil {
|
||||
mgr.Email = email.(string)
|
||||
}
|
||||
if acmeCA := h.Option("acme_ca"); acmeCA != nil {
|
||||
mgr.CA = acmeCA.(string)
|
||||
}
|
||||
|
||||
for h.Next() {
|
||||
// file certificate loader
|
||||
firstLine := h.RemainingArgs()
|
||||
|
@ -112,7 +120,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
|||
hasBlock = true
|
||||
|
||||
switch h.Val() {
|
||||
|
||||
// connection policy
|
||||
case "protocols":
|
||||
args := h.RemainingArgs()
|
||||
|
@ -164,7 +171,8 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
|||
}
|
||||
mgr.CA = arg[0]
|
||||
|
||||
// TODO: other properties for automation manager
|
||||
default:
|
||||
return nil, h.Errf("unknown subdirective: %s", h.Val())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,11 +80,17 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
|
|||
// Caddyfile tokens.
|
||||
type Helper struct {
|
||||
*caddyfile.Dispenser
|
||||
options map[string]interface{}
|
||||
warnings *[]caddyconfig.Warning
|
||||
matcherDefs map[string]map[string]json.RawMessage
|
||||
parentBlock caddyfile.ServerBlock
|
||||
}
|
||||
|
||||
// Option gets the option keyed by name.
|
||||
func (h Helper) Option(name string) interface{} {
|
||||
return h.options[name]
|
||||
}
|
||||
|
||||
// Caddyfiles returns the list of config files from
|
||||
// which tokens in the current server block were loaded.
|
||||
func (h Helper) Caddyfiles() []string {
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httpcaddyfile
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
func (st *ServerType) parseMatcherDefinitions(d *caddyfile.Dispenser) (map[string]map[string]json.RawMessage, error) {
|
||||
matchers := make(map[string]map[string]json.RawMessage)
|
||||
for d.Next() {
|
||||
definitionName := d.Val()
|
||||
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
||||
matcherName := d.Val()
|
||||
mod, err := caddy.GetModule("http.matchers." + matcherName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
|
||||
}
|
||||
unm, ok := mod.New().(caddyfile.Unmarshaler)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
|
||||
}
|
||||
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rm, ok := unm.(caddyhttp.RequestMatcher)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
|
||||
}
|
||||
if _, ok := matchers[definitionName]; !ok {
|
||||
matchers[definitionName] = make(map[string]json.RawMessage)
|
||||
}
|
||||
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
|
||||
}
|
||||
}
|
||||
return matchers, nil
|
||||
}
|
|
@ -58,6 +58,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
var val interface{}
|
||||
var err error
|
||||
disp := caddyfile.NewDispenser(segment)
|
||||
// TODO: make this switch into a map
|
||||
switch dir {
|
||||
case "http_port":
|
||||
val, err = parseOptHTTPPort(disp)
|
||||
|
@ -69,6 +70,10 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
val, err = parseOptExperimentalHTTP3(disp)
|
||||
case "storage":
|
||||
val, err = parseOptStorage(disp)
|
||||
case "acme_ca":
|
||||
val, err = parseOptACMECA(disp)
|
||||
case "email":
|
||||
val, err = parseOptEmail(disp)
|
||||
default:
|
||||
return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
|
||||
}
|
||||
|
@ -108,7 +113,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
|
||||
// extract matcher definitions
|
||||
d := sb.block.DispenseDirective("matcher")
|
||||
matcherDefs, err := st.parseMatcherDefinitions(d)
|
||||
matcherDefs, err := parseMatcherDefinitions(d)
|
||||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
|
@ -122,6 +127,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
if dirFunc, ok := registeredDirectives[dir]; ok {
|
||||
results, err := dirFunc(Helper{
|
||||
Dispenser: caddyfile.NewDispenser(segment),
|
||||
options: options,
|
||||
warnings: &warnings,
|
||||
matcherDefs: matcherDefs,
|
||||
parentBlock: sb.block,
|
||||
|
@ -166,7 +172,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
// now for the TLS app! (TODO: refactor into own func)
|
||||
tlsApp := caddytls.TLS{Certificates: make(map[string]json.RawMessage)}
|
||||
for _, p := range pairings {
|
||||
for _, sblock := range p.serverBlocks {
|
||||
for i, sblock := range p.serverBlocks {
|
||||
// tls automation policies
|
||||
if mmVals, ok := sblock.pile["tls.automation_manager"]; ok {
|
||||
for _, mmVal := range mmVals {
|
||||
|
@ -175,10 +181,16 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
|
||||
Hosts: sblockHosts,
|
||||
ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID(), &warnings),
|
||||
})
|
||||
if len(sblockHosts) > 0 {
|
||||
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
|
||||
Hosts: sblockHosts,
|
||||
ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID(), &warnings),
|
||||
})
|
||||
} else {
|
||||
warnings = append(warnings, caddyconfig.Warning{
|
||||
Message: fmt.Sprintf("Server block %d %v has no names that qualify for automatic HTTPS, so no TLS automation policy will be added.", i, sblock.block.Keys),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,8 +204,25 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
}
|
||||
}
|
||||
}
|
||||
// consolidate automation policies that are the exact same
|
||||
tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies)
|
||||
// if global ACME CA or email were set, append a catch-all automation
|
||||
// policy that ensures they will be used if no tls directive was used
|
||||
acmeCA, hasACMECA := options["acme_ca"]
|
||||
email, hasEmail := options["email"]
|
||||
if hasACMECA || hasEmail {
|
||||
if tlsApp.Automation == nil {
|
||||
tlsApp.Automation = new(caddytls.AutomationConfig)
|
||||
}
|
||||
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
|
||||
ManagementRaw: caddyconfig.JSONModuleObject(caddytls.ACMEManagerMaker{
|
||||
CA: acmeCA.(string),
|
||||
Email: email.(string),
|
||||
}, "module", "acme", &warnings),
|
||||
})
|
||||
}
|
||||
if tlsApp.Automation != nil {
|
||||
// consolidate automation policies that are the exact same
|
||||
tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies)
|
||||
}
|
||||
|
||||
// if experimental HTTP/3 is enabled, enable it on each server
|
||||
if enableH3, ok := options["experimental_http3"].(bool); ok && enableH3 {
|
||||
|
@ -207,7 +236,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
if !reflect.DeepEqual(httpApp, caddyhttp.App{}) {
|
||||
cfg.AppsRaw["http"] = caddyconfig.JSON(httpApp, &warnings)
|
||||
}
|
||||
if !reflect.DeepEqual(tlsApp, caddytls.TLS{}) {
|
||||
if !reflect.DeepEqual(tlsApp, caddytls.TLS{Certificates: make(map[string]json.RawMessage)}) {
|
||||
cfg.AppsRaw["tls"] = caddyconfig.JSON(tlsApp, &warnings)
|
||||
}
|
||||
if storageCvtr, ok := options["storage"].(caddy.StorageConverter); ok {
|
||||
|
@ -415,10 +444,10 @@ func consolidateAutomationPolicies(aps []caddytls.AutomationPolicy) []caddytls.A
|
|||
}
|
||||
if reflect.DeepEqual(aps[i].ManagementRaw, aps[j].ManagementRaw) {
|
||||
aps[i].Hosts = append(aps[i].Hosts, aps[j].Hosts...)
|
||||
aps = append(aps[:j], aps[j+1:]...)
|
||||
i--
|
||||
break
|
||||
}
|
||||
aps = append(aps[:j], aps[j+1:]...)
|
||||
i--
|
||||
break
|
||||
}
|
||||
}
|
||||
return aps
|
||||
|
@ -531,6 +560,37 @@ func (st *ServerType) compileEncodedMatcherSets(sblock caddyfile.ServerBlock) ([
|
|||
return matcherSetsEnc, nil
|
||||
}
|
||||
|
||||
func parseMatcherDefinitions(d *caddyfile.Dispenser) (map[string]map[string]json.RawMessage, error) {
|
||||
matchers := make(map[string]map[string]json.RawMessage)
|
||||
for d.Next() {
|
||||
definitionName := d.Val()
|
||||
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
||||
matcherName := d.Val()
|
||||
mod, err := caddy.GetModule("http.matchers." + matcherName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
|
||||
}
|
||||
unm, ok := mod.New().(caddyfile.Unmarshaler)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
|
||||
}
|
||||
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rm, ok := unm.(caddyhttp.RequestMatcher)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
|
||||
}
|
||||
if _, ok := matchers[definitionName]; !ok {
|
||||
matchers[definitionName] = make(map[string]json.RawMessage)
|
||||
}
|
||||
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
|
||||
}
|
||||
}
|
||||
return matchers, nil
|
||||
}
|
||||
|
||||
func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (map[string]json.RawMessage, error) {
|
||||
msEncoded := make(map[string]json.RawMessage)
|
||||
for matcherName, val := range matchers {
|
||||
|
|
|
@ -108,3 +108,27 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
|
|||
}
|
||||
return storage, nil
|
||||
}
|
||||
|
||||
func parseOptACMECA(d *caddyfile.Dispenser) (string, error) {
|
||||
d.Next() // consume parameter name
|
||||
if !d.Next() {
|
||||
return "", d.ArgErr()
|
||||
}
|
||||
val := d.Val()
|
||||
if d.Next() {
|
||||
return "", d.ArgErr()
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
|
||||
d.Next() // consume parameter name
|
||||
if !d.Next() {
|
||||
return "", d.ArgErr()
|
||||
}
|
||||
val := d.Val()
|
||||
if d.Next() {
|
||||
return "", d.ArgErr()
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue