ICryptoProvider trait

This commit is contained in:
Dmitry Belyaev 2024-10-20 14:29:19 +03:00
parent 21d6eb268a
commit 023f262fea
Signed by: b4tman
GPG Key ID: 41A00BF15EA7E5F3

View File

@ -6,6 +6,7 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
path::{Path, PathBuf}, path::{Path, PathBuf},
pin::Pin, pin::Pin,
sync::Arc,
}; };
use tokio::{ use tokio::{
fs::{self, File}, 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<String, String>,
base_dir: PathBuf, base_dir: PathBuf,
encoding: String, openssl_cnf: PathBuf,
req_days: u32, openssl: String,
ca_file: PathBuf, ca_file: PathBuf,
req_file: PathBuf, req_file: PathBuf,
key_file: PathBuf, key_file: PathBuf,
cert_file: PathBuf, cert_file: PathBuf,
config_file: PathBuf, req_days: u32,
template_file: PathBuf,
openssl_cnf: PathBuf,
openssl: String,
vars: BTreeMap<String, String>,
} }
impl Certs { impl OpenSSLProvider {
fn new(cfg: &AppConfig, vars: BTreeMap<String, String>) -> 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,
}
}
async fn is_ca_exists(&self) -> bool { async fn is_ca_exists(&self) -> bool {
is_file_exist(&self.ca_file).await 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 { async fn is_cert_exists(&self) -> bool {
is_file_exist(&self.cert_file).await is_file_exist(&self.cert_file).await
} }
@ -351,6 +319,39 @@ impl Certs {
is_file_exist(&self.req_file).await is_file_exist(&self.req_file).await
} }
fn from_cfg(cfg: &AppConfig, vars: BTreeMap<String, String>) -> 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<()> { async fn request(&self) -> Result<()> {
if self.is_req_exists().await { if self.is_req_exists().await {
return Ok(()); return Ok(());
@ -422,6 +423,57 @@ impl Certs {
false => Err(anyhow!("ssl ca execution failed")), false => Err(anyhow!("ssl ca execution failed")),
} }
} }
}
struct Certs<T>
where
T: ICryptoProvider,
{
encoding: String,
ca_file: PathBuf,
key_file: PathBuf,
cert_file: PathBuf,
config_file: PathBuf,
template_file: PathBuf,
provider: Arc<T>,
}
fn make_certs_provider(cfg: &AppConfig, vars: BTreeMap<String, String>) -> impl ICryptoProvider {
OpenSSLProvider::from_cfg(cfg, vars)
}
impl<T> Certs<T>
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<bool> { async fn build_client_config(&self) -> Result<bool> {
if self.is_config_exists().await { if self.is_config_exists().await {
@ -470,7 +522,8 @@ async fn main() -> Result<()> {
println!("found vars: {}", vars.filepath.to_str().expect("fff")); println!("found vars: {}", vars.filepath.to_str().expect("fff"));
println!("loaded: {:#?}", &vars.vars); 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 created = certs.build_client_config().await?;
let result_file = certs.config_file.to_str().unwrap(); let result_file = certs.config_file.to_str().unwrap();