diff --git a/acmed/src/config.rs b/acmed/src/config.rs index 5810905..3bdb201 100644 --- a/acmed/src/config.rs +++ b/acmed/src/config.rs @@ -5,7 +5,7 @@ use acme_common::crypto::{HashFunction, KeyType}; use acme_common::error::Error; use glob::glob; use log::info; -use serde::Deserialize; +use serde::{de, Deserialize, Deserializer}; use std::collections::HashMap; use std::fmt; use std::fs::{self, File}; @@ -421,6 +421,7 @@ impl Certificate { } #[derive(Clone, Debug, Deserialize)] +#[serde(remote = "Self")] #[serde(deny_unknown_fields)] pub struct Identifier { pub challenge: String, @@ -430,6 +431,26 @@ pub struct Identifier { pub env: HashMap, } +impl<'de> Deserialize<'de> for Identifier { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let unchecked = Identifier::deserialize(deserializer)?; + let filled_nb: u8 = [unchecked.dns.is_some(), unchecked.ip.is_some()] + .iter() + .copied() + .map(u8::from) + .sum(); + if filled_nb != 1 { + return Err(de::Error::custom( + "one and only one of `dns` or `ip` must be specified", + )); + } + Ok(unchecked) + } +} + impl fmt::Display for Identifier { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = String::new();