mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 10:37:24 -04: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
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user