use std::net::SocketAddr; use std::time::Duration; use serde::{Deserialize, Deserializer}; use crate::models::name::SerdeName; use crate::dns::TsigAlgorithm; #[derive(Debug, Deserialize)] pub struct Config { pub dns: DnsClientConfig, pub web_app: WebAppConfig, } #[derive(Debug, Deserialize)] pub struct DnsClientConfig { pub server: SocketAddr, #[serde(deserialize_with = "from_std_duration")] pub timeout: Duration, pub tsig: Option, } #[derive(Debug, Deserialize)] pub struct TsigConfig { pub name: SerdeName, #[serde(deserialize_with = "from_base64")] pub key: Vec, #[serde(deserialize_with = "from_tsigalg")] pub algorithm: TsigAlgorithm, } #[derive(Debug, Deserialize)] pub struct WebAppConfig { #[serde(deserialize_with = "from_std_duration")] pub token_duration: Duration, } fn from_std_duration<'de, D>(deserializer: D) -> Result where D: Deserializer<'de> { use serde::de::Error; String::deserialize(deserializer) .and_then(|string| humantime::parse_duration(&string).map_err(|err| Error::custom(err.to_string()))) } fn from_base64<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de> { use serde::de::Error; String::deserialize(deserializer) .and_then(|string| base64::decode(&string).map_err(|err| Error::custom(err.to_string()))) } fn from_tsigalg<'de, D>(deserializer: D) -> Result where D: Deserializer<'de> { use serde::de::Error; let algo = match String::deserialize(deserializer)?.as_str() { "hmac-sha256" => TsigAlgorithm::HmacSha256, "hmac-sha384" => TsigAlgorithm::HmacSha384, "hmac-sha512" => TsigAlgorithm::HmacSha512, _ => return Err(Error::custom("Unsupported mac algorithm")) }; if !algo.supported() { Err(Error::custom("Unsupported mac algorithm")) } else { Ok(algo) } }