use crate::algorithm::Algorithm; use crate::canonicalization::Canonicalization; use clap::Parser; use std::collections::HashSet; use std::fs::File; //use std::io::BufReader; use std::io::{BufRead, BufReader}; use std::path::PathBuf; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] pub struct Config { #[arg(short, long, default_value_t = Algorithm::default())] algorithm: Algorithm, #[arg(short, long, default_value_t = Canonicalization::default())] canonicalization: Canonicalization, #[arg(short, long)] domain: Vec<String>, #[arg(short = 'D', long, value_name = "FILE")] domain_file: Option<PathBuf>, #[arg(short, long)] header: Vec<String>, #[arg(short = 'o', long)] header_optional: Vec<String>, #[arg(short, long, value_name = "FILE")] revocation_list: Option<PathBuf>, #[arg(short = 'x', long, default_value_t = 1296000)] expiration: u64, } impl Config { pub fn init() -> Result<Self, String> { let mut cnf = Self::parse(); // domains let mut domain_set: HashSet<String> = cnf.domain.into_iter().collect(); if let Some(path) = &cnf.domain_file { let f = File::open(path).map_err(|e| format!("{}: {e}", path.display()))?; for line in BufReader::new(f).lines() { let line = line.map_err(|e| format!("{}: {e}", path.display()))?; let domain = line.trim(); if !domain.is_empty() && !domain.starts_with('#') { domain_set.insert(domain.to_string()); } } } cnf.domain = domain_set.into_iter().collect::<Vec<_>>(); // headers cnf.header = process_headers(&cnf.header, crate::DEFAULT_HEADERS); cnf.header_optional = process_headers(&cnf.header_optional, crate::DEFAULT_HEADERS_OPT); Ok(cnf) } pub fn algorithm(&self) -> Algorithm { self.algorithm } pub fn canonicalization(&self) -> Canonicalization { self.canonicalization } pub fn domains(&self) -> &[String] { &self.domain } pub fn expiration(&self) -> Option<u64> { if self.expiration != 0 { Some(self.expiration) } else { None } } pub fn headers(&self) -> &[String] { &self.header } pub fn headers_optional(&self) -> &[String] { &self.header_optional } } fn process_headers(lst: &[String], default: &str) -> Vec<String> { let ret = if lst.is_empty() { let default_lst = vec![default.to_string()]; do_process_headers(&default_lst) } else { do_process_headers(lst) }; ret.into_iter().collect::<Vec<_>>() } fn do_process_headers(lst: &[String]) -> HashSet<String> { let mut ret = HashSet::with_capacity(128); for input in lst { for h in input.split(':') { ret.insert(h.to_string().to_lowercase()); } //let mut input_headers: Vec<String> = input.split(':').map(|e| e.to_string()).collect(); //ret.append(&mut input_headers); } ret }