mannequin/src/config.rs
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
/// Configuration for holger-mannequin.
/// If cert fields are empty/None, fresh certs are generated at startup.
/// Otherwise, the supplied certs (inline PEM or file paths) are used.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MannequinConfig {
#[serde(default = "default_port")]
pub port: u16,
/// CA certificate: inline PEM string or file path
#[serde(default)]
pub ca_cert: Option<CertSource>,
/// CA private key: inline PEM string or file path
#[serde(default)]
pub ca_key: Option<CertSource>,
/// Default server cert: inline PEM string or file path
#[serde(default)]
pub server_cert: Option<CertSource>,
/// Default server key: inline PEM string or file path
#[serde(default)]
pub server_key: Option<CertSource>,
}
/// A certificate/key can be supplied inline (base64/PEM) or as a file path.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CertSource {
Inline(String),
File { path: PathBuf },
}
impl CertSource {
pub fn resolve(&self) -> anyhow::Result<String> {
match self {
CertSource::Inline(pem) => Ok(pem.clone()),
CertSource::File { path } => std::fs::read_to_string(path)
.map_err(|e| anyhow::anyhow!("Failed to read {}: {}", path.display(), e)),
}
}
}
fn default_port() -> u16 {
9999
}
impl MannequinConfig {
/// Load from a RON file, or return default (generate everything).
pub fn load(path: &std::path::Path) -> anyhow::Result<Self> {
let file = std::fs::File::open(path)?;
let reader = std::io::BufReader::new(file);
let config: MannequinConfig = ron::de::from_reader(reader)?;
Ok(config)
}
/// Returns true if CA certs are supplied (don't generate).
pub fn has_ca(&self) -> bool {
self.ca_cert.is_some() && self.ca_key.is_some()
}
}