Browse Source

Use a table of table for the endpoints

ng
Rodolphe Bréard 1 month ago
parent
commit
1fbb7c4e4b
Failed to extract signature
  1. 6
      config/20_letsencrypt.toml
  2. 9
      man/en/acmed.toml.5
  3. 16
      src/config.rs
  4. 16
      src/config/endpoint.rs
  5. 7
      tests/config/override/00_initial.toml
  6. 7
      tests/config/override/01_override.toml

6
config/20_letsencrypt.toml

@ -3,14 +3,12 @@ name = "Let's Encrypt rate-limit"
number = 20
period = "1s"
[[endpoint]]
name = "Let's Encrypt v2 production"
[endpoint."letsencrypt-v2-production"]
url = "https://acme-v02.api.letsencrypt.org/directory"
rate_limits = ["Let's Encrypt rate-limit"]
tos_agreed = false
[[endpoint]]
name = "Let's Encrypt v2 staging"
[endpoint."letsencrypt-v2-staging"]
url = "https://acme-staging-v02.api.letsencrypt.org/directory"
rate_limits = ["Let's Encrypt rate-limit"]
tos_agreed = false

9
man/en/acmed.toml.5

@ -237,7 +237,7 @@ Table where the certificate's subject attributes are specified. Possible keys, w
.El
.El
.It Ic endpoint
Array of table where each element defines a Certificate Authority
Table of table where each element defines a Certificate Authority
.Pq CA
which may be used to request certificates.
.Bl -tag
@ -247,8 +247,6 @@ Template used to build the file's name. For detailed documentation, see the
directive located in the
.Em certificate
element.
.It Cm name Ar string
The name the endpoint is registered under. Must be unique.
.It Cm rate_limits Ar array
Array containing the names of the HTTPS rate limits to apply.
.It Cm random_early_renew Ar string
@ -747,8 +745,7 @@ Default certificates and associated private keys directory.
.Sh EXAMPLES
The following example defines a typical endpoint, account and certificate for a domain, several subdomains and an IP address.
.Bd -literal -offset indent
[[endpoint]]
name = "example name"
[endpoint."example-name"]
url = "https://acme.example.org/directory"
tos_agreed = true
@ -759,7 +756,7 @@ contacts = [
]
[[certificate]]
endpoint = "example name"
endpoint = "example-name"
account = "my test account"
identifiers = [
{ dns = "exemple.net", challenge = "http-01"},

16
src/config.rs

@ -17,6 +17,7 @@ pub use rate_limit::*;
use anyhow::{Context, Result};
use config::{Config, File};
use serde_derive::Deserialize;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
@ -27,7 +28,7 @@ const ALLOWED_FILE_EXT: &[&str] = &["toml"];
pub struct AcmedConfig {
pub(in crate::config) global: Option<GlobalOptions>,
#[serde(default)]
pub(in crate::config) endpoint: Vec<Endpoint>,
pub(in crate::config) endpoint: HashMap<String, Endpoint>,
#[serde(default, rename = "rate-limit")]
pub(in crate::config) rate_limit: Vec<RateLimit>,
#[serde(default)]
@ -146,7 +147,18 @@ mod tests {
PathBuf::from("/tmp/example/cert/dir")
);
assert!(cfg.rate_limit.is_empty());
assert!(cfg.endpoint.is_empty());
assert_eq!(cfg.endpoint.len(), 2);
println!("Debug: cfg.endpoint: {:?}", cfg.endpoint);
let ac1 = cfg.endpoint.get("test ac 1").unwrap();
assert_eq!(ac1.url, "https://acme-v02.ac1.example.org/directory");
assert_eq!(ac1.tos_agreed, true);
assert!(ac1.random_early_renew.is_none());
assert!(ac1.root_certificates.is_empty());
let ac2 = cfg.endpoint.get("test ac 2").unwrap();
assert_eq!(ac2.url, "https://acme-v02.ac2.example.org/directory");
assert_eq!(ac2.tos_agreed, false);
assert_eq!(ac2.random_early_renew, Some(Duration::from_secs(10)));
assert_eq!(ac2.root_certificates, vec![PathBuf::from("test.pem")]);
assert!(cfg.hook.is_empty());
assert!(cfg.group.is_empty());
assert_eq!(cfg.account.len(), 1);

16
src/config/endpoint.rs

@ -6,7 +6,6 @@ use std::path::PathBuf;
#[serde(deny_unknown_fields)]
pub struct Endpoint {
pub(in crate::config) file_name_format: Option<String>,
pub(in crate::config) name: String,
pub(in crate::config) random_early_renew: Option<Duration>,
#[serde(default)]
pub(in crate::config) rate_limits: Vec<String>,
@ -31,14 +30,10 @@ mod tests {
#[test]
fn minimal() {
let cfg = r#"
name = "test"
url = "https://acme-v02.api.example.com/directory"
"#;
let cfg = r#"url = "https://acme-v02.api.example.com/directory""#;
let e: Endpoint = load_str(cfg).unwrap();
assert!(e.file_name_format.is_none());
assert_eq!(e.name, "test");
assert!(e.random_early_renew.is_none());
assert!(e.rate_limits.is_empty());
assert!(e.renew_delay.is_none());
@ -50,7 +45,6 @@ url = "https://acme-v02.api.example.com/directory"
#[test]
fn full() {
let cfg = r#"
name = "test"
url = "https://acme-v02.api.example.com/directory"
file_name_format = "{{ key_type }} {{ file_type }} {{ name }}.{{ ext }}"
random_early_renew = "1d"
@ -65,7 +59,6 @@ tos_agreed = true
e.file_name_format,
Some("{{ key_type }} {{ file_type }} {{ name }}.{{ ext }}".to_string())
);
assert_eq!(e.name, "test");
assert_eq!(e.random_early_renew, Some(Duration::from_days(1)));
assert_eq!(e.rate_limits, vec!["rl 1", "rl 2"]);
assert_eq!(e.renew_delay, Some(Duration::from_days(21)));
@ -75,8 +68,11 @@ tos_agreed = true
}
#[test]
fn missing_name() {
let cfg = r#""#;
fn missing_url() {
let cfg = r#"
root_certificates = ["root_cert.pem"]
tos_agreed = true
"#;
let res = load_str::<Endpoint>(cfg);
assert!(res.is_err());

7
tests/config/override/00_initial.toml

@ -2,6 +2,13 @@
accounts_directory = "/tmp/example/account/dir"
certificates_directory = "/tmp/example/cert/dir/"
[endpoint."test AC 1"]
url = "https://acme-v02.ac1.example.org/directory"
tos_agreed = false
[endpoint."test AC 2"]
url = "https://acme-v02.ac2.example.org/directory"
[[account]]
name = "example"
contacts = [

7
tests/config/override/01_override.toml

@ -1 +1,8 @@
global.accounts_directory = "/tmp/other/account/dir"
endpoint."test ac 2".random_early_renew = "10s"
endpoint."test AC 1".tos_agreed = true
[endpoint."test AC 2"]
root_certificates = ["test.pem"]
Loading…
Cancel
Save