diff --git a/src/main.rs b/src/main.rs index 90281d5..bd6b8a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use std::{ collections::BTreeMap, path::{Path, PathBuf}, pin::Pin, + sync::Arc, }; use tokio::{ fs::{self, File}, @@ -288,61 +289,28 @@ impl VarsFile { } } -struct Certs { +trait ICryptoProvider { + async fn request(&self) -> Result<()>; + async fn sign(&self) -> Result<()>; +} + +struct OpenSSLProvider { + vars: BTreeMap, base_dir: PathBuf, - encoding: String, - req_days: u32, + openssl_cnf: PathBuf, + openssl: String, ca_file: PathBuf, req_file: PathBuf, key_file: PathBuf, cert_file: PathBuf, - config_file: PathBuf, - template_file: PathBuf, - openssl_cnf: PathBuf, - openssl: String, - vars: BTreeMap, + req_days: u32, } -impl Certs { - fn new(cfg: &AppConfig, vars: BTreeMap) -> Self { - let base_dir = PathBuf::from(&cfg.base_directory); - let keys_dir = base_dir.clone().join(cfg.keys_subdir.clone()); - let config_dir = base_dir.clone().join(cfg.config_subdir.clone()); - - let mut vars = vars; - let name = cfg.name.clone(); - - vars.insert("KEY_CN".into(), name.clone()); - vars.insert("KEY_NAME".into(), name.clone()); - vars.insert("KEY_EMAIL".into(), cfg.email.clone()); - - Self { - base_dir: base_dir.clone(), - encoding: cfg.encoding.clone(), - req_days: cfg.req_days, - ca_file: keys_dir.join(cfg.ca_filename.clone()), - req_file: keys_dir.join(format!("{}.csr", &name)), - key_file: keys_dir.join(format!("{}.key", &name)), - cert_file: keys_dir.join(format!("{}.crt", &name)), - config_file: config_dir.join(format!("{}.ovpn", &name)), - template_file: base_dir.clone().join(cfg.template_file.clone()), - openssl_cnf: base_dir.clone().join( - std::env::var(cfg.openssl_cnf_env.clone()) - .unwrap_or(cfg.openssl_default_cnf.clone()), - ), - openssl: cfg.openssl.clone(), - vars, - } - } - +impl OpenSSLProvider { async fn is_ca_exists(&self) -> bool { is_file_exist(&self.ca_file).await } - async fn is_config_exists(&self) -> bool { - is_file_exist(&self.config_file).await - } - async fn is_cert_exists(&self) -> bool { is_file_exist(&self.cert_file).await } @@ -351,6 +319,39 @@ impl Certs { is_file_exist(&self.req_file).await } + fn from_cfg(cfg: &AppConfig, vars: BTreeMap) -> Self { + let base_dir = PathBuf::from(&cfg.base_directory); + let keys_dir = base_dir.clone().join(cfg.keys_subdir.clone()); + let name = cfg.name.clone(); + let mut vars = vars; + + vars.insert("KEY_CN".into(), name.clone()); + vars.insert("KEY_NAME".into(), name.clone()); + vars.insert("KEY_EMAIL".into(), cfg.email.clone()); + + let ca_file = keys_dir.join(cfg.ca_filename.clone()); + let req_file = keys_dir.join(format!("{}.csr", &name)); + let key_file = keys_dir.join(format!("{}.key", &name)); + let cert_file = keys_dir.join(format!("{}.crt", &name)); + let openssl_cnf = base_dir.clone().join( + std::env::var(cfg.openssl_cnf_env.clone()).unwrap_or(cfg.openssl_default_cnf.clone()), + ); + + Self { + vars, + base_dir, + openssl_cnf, + openssl: cfg.openssl.clone(), + ca_file, + req_file, + key_file, + cert_file, + req_days: cfg.req_days, + } + } +} + +impl ICryptoProvider for OpenSSLProvider { async fn request(&self) -> Result<()> { if self.is_req_exists().await { return Ok(()); @@ -422,6 +423,57 @@ impl Certs { false => Err(anyhow!("ssl ca execution failed")), } } +} + +struct Certs +where + T: ICryptoProvider, +{ + encoding: String, + ca_file: PathBuf, + key_file: PathBuf, + cert_file: PathBuf, + config_file: PathBuf, + template_file: PathBuf, + provider: Arc, +} + +fn make_certs_provider(cfg: &AppConfig, vars: BTreeMap) -> impl ICryptoProvider { + OpenSSLProvider::from_cfg(cfg, vars) +} + +impl Certs +where + T: ICryptoProvider, +{ + fn new(cfg: &AppConfig, provider: T) -> Self { + let base_dir = PathBuf::from(&cfg.base_directory); + let keys_dir = base_dir.clone().join(cfg.keys_subdir.clone()); + let config_dir = base_dir.clone().join(cfg.config_subdir.clone()); + let name = cfg.name.clone(); + + Certs { + encoding: cfg.encoding.clone(), + ca_file: keys_dir.join(cfg.ca_filename.clone()), + key_file: keys_dir.join(format!("{}.key", &name)), + cert_file: keys_dir.join(format!("{}.crt", &name)), + config_file: config_dir.join(format!("{}.ovpn", &name)), + template_file: base_dir.clone().join(cfg.template_file.clone()), + provider: Arc::new(provider), + } + } + + async fn is_config_exists(&self) -> bool { + is_file_exist(&self.config_file).await + } + + async fn request(&self) -> Result<()> { + self.provider.request().await + } + + async fn sign(&self) -> Result<()> { + self.provider.sign().await + } async fn build_client_config(&self) -> Result { if self.is_config_exists().await { @@ -470,7 +522,8 @@ async fn main() -> Result<()> { println!("found vars: {}", vars.filepath.to_str().expect("fff")); println!("loaded: {:#?}", &vars.vars); - let certs = Certs::new(&config, vars.vars.unwrap()); + let provider = make_certs_provider(&config, vars.vars.unwrap()); + let certs = Certs::new(&config, provider); let created = certs.build_client_config().await?; let result_file = certs.config_file.to_str().unwrap();