use ipnet::IpNet;
use once_cell::sync::OnceCell;
use std::{collections::HashSet, net::IpAddr};
#[derive(Clone, Debug)]
pub struct ConfigBuilder {
has_trusted_networks: bool,
trusted_networks: HashSet<IpNet>,
auth_untrusted: bool,
spamc_args: Vec<String>,
max_message_size: usize,
dry_run: bool,
reject_spam: bool,
preserve_headers: bool,
preserve_body: bool,
verbose: bool,
}
impl ConfigBuilder {
pub fn set_has_trusted_networks(&mut self, value: bool) -> &mut Self {
self.has_trusted_networks = value;
self
}
pub fn add_trusted_network(&mut self, value: IpNet) -> &mut Self {
self.has_trusted_networks = true;
self.trusted_networks.insert(value);
self
}
pub fn set_auth_untrusted(&mut self, value: bool) -> &mut Self {
self.auth_untrusted = value;
self
}
pub fn set_spamc_args(&mut self, value: Vec<String>) -> &mut Self {
self.spamc_args = value;
self
}
pub fn set_max_message_size(&mut self, value: usize) -> &mut Self {
self.max_message_size = value;
self
}
pub fn set_dry_run(&mut self, value: bool) -> &mut Self {
self.dry_run = value;
self
}
pub fn set_reject_spam(&mut self, value: bool) -> &mut Self {
self.reject_spam = value;
self
}
pub fn set_preserve_headers(&mut self, value: bool) -> &mut Self {
self.preserve_headers = value;
self
}
pub fn set_preserve_body(&mut self, value: bool) -> &mut Self {
self.preserve_body = value;
self
}
pub fn set_verbose(&mut self, value: bool) -> &mut Self {
self.verbose = value;
self
}
pub fn build(self) -> Config {
Config {
has_trusted_networks: self.has_trusted_networks,
trusted_networks: self.trusted_networks,
auth_untrusted: self.auth_untrusted,
spamc_args: self.spamc_args,
max_message_size: self.max_message_size,
dry_run: self.dry_run,
reject_spam: self.reject_spam,
preserve_headers: self.preserve_headers,
preserve_body: self.preserve_body,
verbose: self.verbose,
}
}
}
impl Default for ConfigBuilder {
fn default() -> Self {
Self {
has_trusted_networks: Default::default(),
trusted_networks: Default::default(),
auth_untrusted: Default::default(),
spamc_args: Default::default(),
max_message_size: 512_000, dry_run: Default::default(),
reject_spam: Default::default(),
preserve_headers: Default::default(),
preserve_body: Default::default(),
verbose: Default::default(),
}
}
}
#[derive(Clone, Debug)]
pub struct Config {
has_trusted_networks: bool,
trusted_networks: HashSet<IpNet>,
auth_untrusted: bool,
spamc_args: Vec<String>,
max_message_size: usize,
dry_run: bool,
reject_spam: bool,
preserve_headers: bool,
preserve_body: bool,
verbose: bool,
}
impl Config {
pub fn builder() -> ConfigBuilder {
Default::default()
}
pub fn has_trusted_networks(&self) -> bool {
self.has_trusted_networks
}
pub fn is_in_trusted_networks(&self, ip: &IpAddr) -> bool {
self.trusted_networks.iter().any(|n| n.contains(ip))
}
pub fn auth_untrusted(&self) -> bool {
self.auth_untrusted
}
pub fn spamc_args(&self) -> &[String] {
&self.spamc_args
}
pub fn max_message_size(&self) -> usize {
self.max_message_size
}
pub fn dry_run(&self) -> bool {
self.dry_run
}
pub fn reject_spam(&self) -> bool {
self.reject_spam
}
pub fn preserve_headers(&self) -> bool {
self.preserve_headers
}
pub fn preserve_body(&self) -> bool {
self.preserve_body
}
pub fn verbose(&self) -> bool {
self.verbose
}
}
impl Default for Config {
fn default() -> Self {
ConfigBuilder::default().build()
}
}
static CONFIG: OnceCell<Config> = OnceCell::new();
pub fn init(config: Config) {
CONFIG.set(config).expect("configuration already initialized")
}
pub fn get() -> &'static Config {
CONFIG.get().expect("configuration not initialized")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trusted_networks_config() {
let mut builder = Config::builder();
builder.add_trusted_network("127.0.0.1/8".parse().unwrap());
let config = builder.build();
assert!(config.has_trusted_networks());
assert!(config.is_in_trusted_networks(&"127.0.0.1".parse().unwrap()));
assert!(!config.is_in_trusted_networks(&"10.1.0.1".parse().unwrap()));
}
}