diff --git a/caddytest/integration/caddyfile_adapt/global_options_ondemand_permission_path.caddyfiletest b/caddytest/integration/caddyfile_adapt/global_options_ondemand_permission_path.caddyfiletest new file mode 100644 index 000000000..e0f54fd9b --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/global_options_ondemand_permission_path.caddyfiletest @@ -0,0 +1,104 @@ +{ + debug + http_port 8080 + https_port 8443 + default_sni localhost + order root first + storage file_system { + root /data + } + acme_ca https://example.com + acme_eab { + key_id 4K2scIVbBpNd-78scadB2g + mac_key abcdefghijklmnopqrstuvwx-abcdefghijklnopqrstuvwxyz12ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh + } + acme_ca_root /path/to/ca.crt + email test@example.com + admin off + on_demand_tls { + permission path /tmp/web + interval 30s + burst 20 + } + storage_clean_interval 7d + renew_interval 1d + ocsp_interval 2d + + key_type ed25519 +} + +:80 +---------- +{ + "admin": { + "disabled": true + }, + "logging": { + "logs": { + "default": { + "level": "DEBUG" + } + } + }, + "storage": { + "module": "file_system", + "root": "/data" + }, + "apps": { + "http": { + "http_port": 8080, + "https_port": 8443, + "servers": { + "srv0": { + "listen": [ + ":80" + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "issuers": [ + { + "ca": "https://example.com", + "challenges": { + "http": { + "alternate_port": 8080 + }, + "tls-alpn": { + "alternate_port": 8443 + } + }, + "email": "test@example.com", + "external_account": { + "key_id": "4K2scIVbBpNd-78scadB2g", + "mac_key": "abcdefghijklmnopqrstuvwx-abcdefghijklnopqrstuvwxyz12ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh" + }, + "module": "acme", + "trusted_roots_pem_files": [ + "/path/to/ca.crt" + ] + } + ], + "key_type": "ed25519" + } + ], + "on_demand": { + "permission": { + "module": "path", + "root_path": "/tmp/web" + }, + "rate_limit": { + "interval": 30000000000, + "burst": 20 + } + }, + "ocsp_interval": 172800000000000, + "renew_interval": 86400000000000, + "storage_clean_interval": 604800000000000 + } + } + } +} diff --git a/modules/caddytls/ondemand_path.go b/modules/caddytls/ondemand_path.go new file mode 100644 index 000000000..41bc8f7f8 --- /dev/null +++ b/modules/caddytls/ondemand_path.go @@ -0,0 +1,68 @@ +package caddytls + +import ( + "context" + "fmt" + "os" + "path" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "go.uber.org/zap" +) + +type PermissionByPath struct { + RootPath string `json:"root_path"` + + logger *zap.Logger + replacer *caddy.Replacer +} + +func (p PermissionByPath) CertificateAllowed(ctx context.Context, name string) error { + askRooPath, err := p.replacer.ReplaceOrErr(p.RootPath, true, true) + if err != nil { + return fmt.Errorf("preparing 'ask' path: %v", err) + } + + filePath := path.Join(askRooPath, name) + if _, err := os.Stat(filePath); err != nil { + return err + } + + return nil +} + +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (p *PermissionByPath) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + if !d.Next() { + return nil + } + if !d.AllArgs(&p.RootPath) { + return d.ArgErr() + } + return nil +} + +func (p *PermissionByPath) Provision(ctx caddy.Context) error { + p.logger = ctx.Logger() + p.replacer = caddy.NewReplacer() + return nil +} + +func init() { + caddy.RegisterModule(PermissionByPath{}) +} + +// CaddyModule returns the Caddy module information. +func (PermissionByPath) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "tls.permission.path", + New: func() caddy.Module { return new(PermissionByPath) }, + } +} + +// Interface guards +var ( + _ OnDemandPermission = (*PermissionByPath)(nil) + _ caddy.Provisioner = (*PermissionByPath)(nil) +)