diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b6937..7dc3317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Instead of loading a default configuration file, ACMEd now loads all the files from a default configuration directory (by default, `/etc/acmed/conf-enabled`). +- The configuration arrays for accounts, endpoints, rate limits, hooks and + groups has been replaced by tables. ### Removed diff --git a/man/en/acmed.toml.5 b/man/en/acmed.toml.5 index 12fe1b9..2b449f4 100644 --- a/man/en/acmed.toml.5 +++ b/man/en/acmed.toml.5 @@ -18,7 +18,7 @@ are written in the format. The allowed elements are described below. .Bl -tag .It Ic account -Table of table representing an account on one or several endpoint. +Table representing an account on one or several endpoint. .Bl -tag .It Ic contacts Ar array Array of tables describing describing the account holder's contact information. Each table must have one and only one key-value pair. Possible keys and their associated values are: @@ -235,7 +235,7 @@ Table where the certificate's subject attributes are specified. Possible keys, w .El .El .It Ic endpoint -Table of table where each element defines a Certificate Authority +Table where each element defines a Certificate Authority .Pq CA which may be used to request certificates. .Bl -tag @@ -321,15 +321,9 @@ section. Default is 30d. Array containing the path to root certificates that should be added to the trust store. .El .It Ic group -Array of table allowing to group several hooks as one. A group is considered as new hook. -.Bl -tag -.It Cm hooks Ar array -Array containing the names of the hooks that are grouped. The hooks are guaranteed to be called sequentially in the declaration order. -.It Cm name Ar string -The name the group is registered under. This name is considered as a hook name. Must be unique. -.El +Table of array allowing to group several hooks as one. A group is considered as new hook. The array contains the names of the hooks that are grouped. The hooks are guaranteed to be called sequentially in the declaration order. .It Ic hook -Array of table where each element defines a command that will be launched at a defined point. See section +Table where each element defines a command that will be launched at a defined point. See section .Sx WRITING A HOOK for more details. .Bl -tag @@ -339,8 +333,6 @@ Defines if an error return value for this hook is allowed or not. If not allowed Array of strings representing the command's arguments. .It Ic cmd Ar string The name of the command that will be launched. -.It Cm name Ar string -The name the hook is registered under. Must be unique. .It Ic stderr Ar string Path to the file where the command's standard error output if written. .It Ic stdin Ar string @@ -379,7 +371,7 @@ post-operation .El .El .It Ic rate-limit -Table of table where each element defines a HTTPS rate limit. +Table where each element defines a HTTPS rate limit. .Bl -tag .It Cm number Ar integer Number of requests authorized withing the time period. diff --git a/src/config.rs b/src/config.rs index 0a3f45d..587a895 100644 --- a/src/config.rs +++ b/src/config.rs @@ -32,9 +32,9 @@ pub struct AcmedConfig { #[serde(default, rename = "rate-limit")] pub(in crate::config) rate_limit: HashMap, #[serde(default)] - pub(in crate::config) hook: Vec, + pub(in crate::config) hook: HashMap, #[serde(default)] - pub(in crate::config) group: Vec, + pub(in crate::config) group: HashMap>, #[serde(default)] pub(in crate::config) account: HashMap, #[serde(default)] @@ -114,12 +114,29 @@ mod tests { global.certificates_directory, PathBuf::from("/tmp/example/cert/dir") ); - assert!(cfg.rate_limit.is_empty()); - assert!(cfg.endpoint.is_empty()); - assert!(cfg.hook.is_empty()); - assert!(cfg.group.is_empty()); + assert_eq!(cfg.rate_limit.len(), 1); + let rl = cfg.rate_limit.get("my-ca-limit").unwrap(); + assert_eq!(rl.number, 20); + assert_eq!(rl.period, Duration::from_secs(1)); + assert_eq!(cfg.endpoint.len(), 1); + let ep = cfg.endpoint.get("my-ca").unwrap(); + assert_eq!(ep.url, "https://acme-v02.ac1.example.org/directory"); + assert_eq!(ep.rate_limits, vec!["my-ca-limit".to_string()]); + assert_eq!(ep.tos_agreed, true); + assert_eq!(cfg.hook.len(), 2); + let h1 = cfg.hook.get("hook-1").unwrap(); + assert_eq!(h1.cmd, "cat"); + assert!(h1.args.is_empty()); + assert_eq!(h1.hook_type, vec![HookType::FilePreEdit]); + let h2 = cfg.hook.get("hook-2").unwrap(); + assert_eq!(h2.cmd, "cat"); + assert_eq!(h2.args, vec!["-e".to_string()]); + assert_eq!(h2.hook_type, vec![HookType::FilePreEdit]); + assert_eq!(cfg.group.len(), 1); + let g1 = cfg.group.get("super-hook").unwrap(); + assert_eq!(*g1, vec!["hook-1".to_string(), "hook-2".to_string()]); assert_eq!(cfg.account.len(), 1); - let account = cfg.account.get("example").unwrap(); + let account = cfg.account.get("toto").unwrap(); assert_eq!(account.contacts.len(), 1); assert!(account.env.is_empty()); assert!(account.external_account.is_none()); @@ -129,7 +146,15 @@ mod tests { account.signature_algorithm, Some(AccountSignatureAlgorithm::Hs384) ); - assert!(cfg.certificate.is_empty()); + assert_eq!(cfg.certificate.len(), 1); + let c = cfg.certificate.first().unwrap(); + assert_eq!(c.account, "toto"); + assert_eq!(c.endpoint, "my-ca"); + assert_eq!(c.identifiers.len(), 1); + let i = c.identifiers.first().unwrap(); + assert_eq!(i.dns, Some("example.org".to_string())); + assert_eq!(i.challenge, AcmeChallenge::Http01); + assert_eq!(c.hooks, vec!["super-hook".to_string()]); } #[test] diff --git a/src/config/hook.rs b/src/config/hook.rs index 76adb8b..99891d4 100644 --- a/src/config/hook.rs +++ b/src/config/hook.rs @@ -11,7 +11,6 @@ pub struct Hook { #[serde(default)] pub(in crate::config) args: Vec, pub(in crate::config) cmd: String, - pub(in crate::config) name: String, pub(in crate::config) stderr: Option, pub(in crate::config) stdin: Option, pub(in crate::config) stdin_str: Option, @@ -62,35 +61,11 @@ pub enum HookType { PostOperation, } -#[derive(Debug, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Group { - pub(in crate::config) hooks: Vec, - pub(in crate::config) name: String, -} - #[cfg(test)] mod tests { use super::*; use crate::config::load_str; - #[test] - fn empty_group() { - let res = load_str::(""); - assert!(res.is_err()); - } - - #[test] - fn valid_group() { - let cfg = r#" -name = "test" -hooks = ["h1", "H 2"] -"#; - let rl: Group = load_str(cfg).unwrap(); - assert_eq!(rl.name, "test"); - assert_eq!(rl.hooks, vec!["h1".to_string(), "H 2".to_string()]); - } - #[test] fn empty_hook() { let res = load_str::(""); @@ -100,7 +75,6 @@ hooks = ["h1", "H 2"] #[test] fn hook_minimal() { let cfg = r#" -name = "test" cmd = "cat" type = ["file-pre-edit"] "#; @@ -108,7 +82,6 @@ type = ["file-pre-edit"] assert_eq!(h.allow_failure, false); assert!(h.args.is_empty()); assert_eq!(h.cmd, "cat"); - assert_eq!(h.name, "test"); assert!(h.stderr.is_none()); assert!(h.stdin.is_none()); assert!(h.stdin_str.is_none()); @@ -119,7 +92,6 @@ type = ["file-pre-edit"] #[test] fn hook_full() { let cfg = r#" -name = "test" cmd = "cat" args = ["-e"] type = ["file-pre-edit"] @@ -132,7 +104,6 @@ stderr = "/tmp/err.log" assert_eq!(h.allow_failure, true); assert_eq!(h.args, vec!["-e".to_string()]); assert_eq!(h.cmd, "cat"); - assert_eq!(h.name, "test"); assert_eq!(h.stderr, Some(PathBuf::from("/tmp/err.log"))); assert_eq!(h.stdin, Some(PathBuf::from("/tmp/in.txt"))); assert!(h.stdin_str.is_none()); @@ -143,7 +114,6 @@ stderr = "/tmp/err.log" #[test] fn hook_both_stdin() { let cfg = r#" -name = "test" cmd = "cat" type = ["file-pre-edit"] stdin = "/tmp/in.txt" @@ -153,20 +123,9 @@ stdin_str = "some input" assert!(res.is_err()); } - #[test] - fn hook_missing_name() { - let cfg = r#" -cmd = "cat" -type = ["file-pre-edit"] -"#; - let res = load_str::(cfg); - assert!(res.is_err()); - } - #[test] fn hook_missing_cmd() { let cfg = r#" -name = "test" type = ["file-pre-edit"] "#; let res = load_str::(cfg); @@ -176,7 +135,6 @@ type = ["file-pre-edit"] #[test] fn hook_missing_type() { let cfg = r#" -name = "test" cmd = "cat" "#; let res = load_str::(cfg); @@ -186,7 +144,6 @@ cmd = "cat" #[test] fn hook_empty_type() { let cfg = r#" -name = "test" cmd = "cat" type = [] "#; diff --git a/tests/config/simple/simple.toml b/tests/config/simple/simple.toml index 2e89999..b6f7663 100644 --- a/tests/config/simple/simple.toml +++ b/tests/config/simple/simple.toml @@ -2,8 +2,39 @@ accounts_directory = "/tmp/example/account/dir" certificates_directory = "/tmp/example/cert/dir/" -[account."example"] +[account."toto"] contacts = [ - { mailto = "acme@example.org" }, + { mailto = "acme@example.org" }, ] signature_algorithm = "HS384" + +[rate-limit."my-ca-limit"] +number = 20 +period = "1s" + +[endpoint."my-ca"] +url = "https://acme-v02.ac1.example.org/directory" +rate_limits = ["my-ca-limit"] +tos_agreed = true + +[hook."hook-1"] +cmd = "cat" +type = ["file-pre-edit"] + +[hook."hook-2"] +cmd = "cat" +args = [ + "-e" +] +type = ["file-pre-edit"] + +[group] +super-hook = ["hook-1", "hook-2"] + +[[certificate]] +account = "toto" +endpoint = "my-ca" +identifiers = [ + { dns = "example.org", challenge = "http-01"}, +] +hooks = ["super-hook"]