diff --git a/acmed/src/account.rs b/acmed/src/account.rs index ea4042c..93ff8bd 100644 --- a/acmed/src/account.rs +++ b/acmed/src/account.rs @@ -1,3 +1,4 @@ +use crate::storage::FileManager; use acme_common::crypto::{JwsSignatureAlgorithm, KeyType}; use acme_common::error::Error; use std::str::FromStr; @@ -12,6 +13,7 @@ pub struct Account { impl Account { pub fn new( + _file_manager: &FileManager, name: &str, email: &str, key_type: &Option, diff --git a/acmed/src/acme_proto.rs b/acmed/src/acme_proto.rs index b598ad8..2e9db53 100644 --- a/acmed/src/acme_proto.rs +++ b/acmed/src/acme_proto.rs @@ -6,6 +6,7 @@ use crate::certificate::Certificate; use crate::endpoint::Endpoint; use crate::identifier::IdentifierType; use crate::jws::encode_kid; +use crate::logs::HasLogger; use crate::storage; use acme_common::crypto::Csr; use acme_common::error::Error; @@ -199,7 +200,7 @@ pub fn request_certificate( .ok_or_else(|| Error::from("No certificate available for download."))?; let data_builder = set_empty_data_builder!(account); let crt = http::get_certificate(endpoint, root_certs, &data_builder, &crt_url)?; - storage::write_certificate(cert, &crt.as_bytes())?; + storage::write_certificate(&cert.file_manager, &crt.as_bytes())?; cert.info(&format!( "Certificate renewed (identifiers: {})", diff --git a/acmed/src/acme_proto/account.rs b/acmed/src/acme_proto/account.rs index c24ae4a..5eddb27 100644 --- a/acmed/src/acme_proto/account.rs +++ b/acmed/src/acme_proto/account.rs @@ -3,6 +3,7 @@ use crate::acme_proto::structs::Account; use crate::certificate::Certificate; use crate::endpoint::Endpoint; use crate::jws::encode_jwk; +use crate::logs::HasLogger; use crate::storage; use acme_common::crypto::{gen_keypair, JwsSignatureAlgorithm, KeyPair}; use acme_common::error::Error; @@ -21,7 +22,7 @@ impl AccountManager { cert: &Certificate, ) -> Result { // TODO: store the key id (account url) - let key_pair = storage::get_account_keypair(cert)?; + let key_pair = storage::get_account_keypair(&cert.file_manager)?; let signature_algorithm = cert.account.signature_algorithm; let kp_ref = &key_pair; let account = Account::new(cert, endpoint); @@ -43,21 +44,21 @@ impl AccountManager { } pub fn init_account(cert: &Certificate) -> Result<(), Error> { - if !storage::account_files_exists(cert) { + if !storage::account_files_exists(&cert.file_manager) { cert.info(&format!( "Account {} does not exists. Creating it.", &cert.account.name )); let key_pair = gen_keypair(cert.account.key_type)?; - storage::set_account_keypair(cert, &key_pair)?; + storage::set_account_keypair(&cert.file_manager, &key_pair)?; cert.debug(&format!("Account {} created.", &cert.account.name)); } else { - let key_pair = storage::get_account_keypair(cert)?; + let key_pair = storage::get_account_keypair(&cert.file_manager)?; if key_pair.key_type != cert.account.key_type { cert.info(&format!("Account {name} has a key pair of type {kt_has} while {kt_want} was expected. Creating a new {kt_want} key pair.", name=&cert.account.name, kt_has=key_pair.key_type, kt_want=cert.account.key_type)); // TODO: Do a propper key rollover let key_pair = gen_keypair(cert.account.key_type)?; - storage::set_account_keypair(cert, &key_pair)?; + storage::set_account_keypair(&cert.file_manager, &key_pair)?; cert.debug(&format!( "Account {} updated with a new {} key pair.", &cert.account.name, cert.account.key_type diff --git a/acmed/src/acme_proto/certificate.rs b/acmed/src/acme_proto/certificate.rs index aee30a0..6e30eff 100644 --- a/acmed/src/acme_proto/certificate.rs +++ b/acmed/src/acme_proto/certificate.rs @@ -5,12 +5,12 @@ use acme_common::error::Error; fn gen_key_pair(cert: &Certificate) -> Result { let key_pair = gen_keypair(cert.key_type)?; - storage::set_keypair(cert, &key_pair)?; + storage::set_keypair(&cert.file_manager, &key_pair)?; Ok(key_pair) } fn read_key_pair(cert: &Certificate) -> Result { - storage::get_keypair(cert) + storage::get_keypair(&cert.file_manager) } pub fn get_key_pair(cert: &Certificate) -> Result { diff --git a/acmed/src/certificate.rs b/acmed/src/certificate.rs index 450ec01..b41812a 100644 --- a/acmed/src/certificate.rs +++ b/acmed/src/certificate.rs @@ -2,7 +2,8 @@ use crate::account::Account; use crate::acme_proto::Challenge; use crate::hooks::{self, ChallengeHookData, Hook, HookEnvData, HookType, PostOperationHookData}; use crate::identifier::{Identifier, IdentifierType}; -use crate::storage::{certificate_files_exists, get_certificate}; +use crate::logs::HasLogger; +use crate::storage::{certificate_files_exists, get_certificate, FileManager}; use acme_common::crypto::{HashFunction, KeyType, X509Certificate}; use acme_common::error::Error; use log::{debug, info, trace, warn}; @@ -19,19 +20,11 @@ pub struct Certificate { pub kp_reuse: bool, pub endpoint_name: String, pub hooks: Vec, - pub account_directory: String, - pub crt_directory: String, pub crt_name: String, - pub crt_name_format: String, - pub cert_file_mode: u32, - pub cert_file_owner: Option, - pub cert_file_group: Option, - pub pk_file_mode: u32, - pub pk_file_owner: Option, - pub pk_file_group: Option, pub env: HashMap, pub id: usize, pub renew_delay: Duration, + pub file_manager: FileManager, } impl fmt::Display for Certificate { @@ -41,23 +34,25 @@ impl fmt::Display for Certificate { } } -impl Certificate { - pub fn warn(&self, msg: &str) { +impl HasLogger for Certificate { + fn warn(&self, msg: &str) { warn!("{}: {}", &self, msg); } - pub fn info(&self, msg: &str) { + fn info(&self, msg: &str) { info!("{}: {}", &self, msg); } - pub fn debug(&self, msg: &str) { + fn debug(&self, msg: &str) { debug!("{}: {}", &self, msg); } - pub fn trace(&self, msg: &str) { + fn trace(&self, msg: &str) { trace!("{}: {}", &self, msg); } +} +impl Certificate { pub fn get_identifier_from_str(&self, identifier: &str) -> Result { let identifier = identifier.to_string(); for d in self.identifiers.iter() { @@ -119,11 +114,11 @@ impl Certificate { "Checking for renewal (identifiers: {})", self.identifier_list() )); - if !certificate_files_exists(&self) { + if !certificate_files_exists(&self.file_manager) { self.debug("certificate does not exist: requesting one"); return Ok(true); } - let cert = get_certificate(&self)?; + let cert = get_certificate(&self.file_manager)?; let renew_ident = self.has_missing_identifiers(&cert); if renew_ident { @@ -169,7 +164,7 @@ impl Certificate { HookType::ChallengeTlsAlpn01Clean, ), }; - hooks::call(self, &hook_data, hook_type.0)?; + hooks::call(self, &self.hooks, &hook_data, hook_type.0)?; Ok((hook_data, hook_type.1)) } @@ -178,7 +173,7 @@ impl Certificate { data: &ChallengeHookData, hook_type: HookType, ) -> Result<(), Error> { - hooks::call(self, data, hook_type) + hooks::call(self, &self.hooks, data, hook_type) } pub fn call_post_operation_hooks(&self, status: &str, is_success: bool) -> Result<(), Error> { @@ -195,7 +190,7 @@ impl Certificate { env: HashMap::new(), }; hook_data.set_env(&self.env); - hooks::call(self, &hook_data, HookType::PostOperation)?; + hooks::call(self, &self.hooks, &hook_data, HookType::PostOperation)?; Ok(()) } } diff --git a/acmed/src/config.rs b/acmed/src/config.rs index 3bdb201..abaf4aa 100644 --- a/acmed/src/config.rs +++ b/acmed/src/config.rs @@ -1,6 +1,7 @@ use crate::duration::parse_duration; use crate::hooks; use crate::identifier::IdentifierType; +use crate::storage::FileManager; use acme_common::crypto::{HashFunction, KeyType}; use acme_common::error::Error; use glob::glob; @@ -87,7 +88,7 @@ impl Config { if name == hook.name { let h = hooks::Hook { name: hook.name.to_owned(), - hook_type: hook.hook_type.to_owned(), + hook_type: hook.hook_type.iter().map(|e| e.to_owned()).collect(), cmd: hook.cmd.to_owned(), args: hook.args.to_owned(), stdin: get_stdin(&hook)?, @@ -242,7 +243,7 @@ pub struct Hook { pub allow_failure: Option, } -#[derive(Clone, Debug, Eq, PartialEq, Deserialize)] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum HookType { FilePreCreate, @@ -281,8 +282,9 @@ pub struct Account { } impl Account { - pub fn to_generic(&self) -> Result { + pub fn to_generic(&self, file_manager: &FileManager) -> Result { crate::account::Account::new( + file_manager, &self.name, &self.email, &self.key_type, @@ -311,10 +313,14 @@ pub struct Certificate { } impl Certificate { - pub fn get_account(&self, cnf: &Config) -> Result { + pub fn get_account( + &self, + cnf: &Config, + file_manager: &FileManager, + ) -> Result { for account in cnf.account.iter() { if account.name == self.account { - let acc = account.to_generic()?; + let acc = account.to_generic(file_manager)?; return Ok(acc); } } diff --git a/acmed/src/hooks.rs b/acmed/src/hooks.rs index 00e2458..f93e39a 100644 --- a/acmed/src/hooks.rs +++ b/acmed/src/hooks.rs @@ -1,10 +1,10 @@ -use crate::certificate::Certificate; pub use crate::config::HookType; +use crate::logs::HasLogger; use acme_common::error::Error; use handlebars::Handlebars; use serde::Serialize; use std::collections::hash_map::Iter; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::prelude::*; use std::io::BufReader; @@ -86,7 +86,7 @@ pub enum HookStdin { #[derive(Clone, Debug)] pub struct Hook { pub name: String, - pub hook_type: Vec, + pub hook_type: HashSet, pub cmd: String, pub args: Option>, pub stdin: HookStdin, @@ -102,11 +102,11 @@ impl fmt::Display for Hook { } macro_rules! get_hook_output { - ($cert: expr, $out: expr, $reg: ident, $data: expr, $hook_name: expr, $out_name: expr) => {{ + ($logger: expr, $out: expr, $reg: ident, $data: expr, $hook_name: expr, $out_name: expr) => {{ match $out { Some(path) => { let path = $reg.render_template(path, $data)?; - $cert.trace(&format!("Hook {}: {}: {}", $hook_name, $out_name, &path)); + $logger.trace(&format!("Hook {}: {}: {}", $hook_name, $out_name, &path)); let file = File::create(&path)?; Stdio::from(file) } @@ -115,11 +115,12 @@ macro_rules! get_hook_output { }}; } -fn call_single(cert: &Certificate, data: &T, hook: &Hook) -> Result<(), Error> +fn call_single(logger: &L, data: &T, hook: &Hook) -> Result<(), Error> where + L: HasLogger, T: Clone + HookEnvData + Serialize, { - cert.debug(&format!("Calling hook: {}", hook.name)); + logger.debug(&format!("Calling hook: {}", hook.name)); let reg = Handlebars::new(); let mut v = vec![]; let args = match &hook.args { @@ -132,13 +133,13 @@ where } None => &[], }; - cert.trace(&format!("Hook {}: cmd: {}", hook.name, hook.cmd)); - cert.trace(&format!("Hook {}: args: {:?}", hook.name, args)); + logger.trace(&format!("Hook {}: cmd: {}", hook.name, hook.cmd)); + logger.trace(&format!("Hook {}: args: {:?}", hook.name, args)); let mut cmd = Command::new(&hook.cmd) .envs(data.get_env()) .args(args) .stdout(get_hook_output!( - cert, + logger, &hook.stdout, reg, &data, @@ -146,7 +147,7 @@ where "stdout" )) .stderr(get_hook_output!( - cert, + logger, &hook.stderr, reg, &data, @@ -161,13 +162,13 @@ where match &hook.stdin { HookStdin::Str(s) => { let data_in = reg.render_template(&s, &data)?; - cert.trace(&format!("Hook {}: string stdin: {}", hook.name, &data_in)); + logger.trace(&format!("Hook {}: string stdin: {}", hook.name, &data_in)); let stdin = cmd.stdin.as_mut().ok_or("stdin not found")?; stdin.write_all(data_in.as_bytes())?; } HookStdin::File(f) => { let file_name = reg.render_template(&f, &data)?; - cert.trace(&format!("Hook {}: file stdin: {}", hook.name, &file_name)); + logger.trace(&format!("Hook {}: file stdin: {}", hook.name, &file_name)); let stdin = cmd.stdin.as_mut().ok_or("stdin not found")?; let file = File::open(&file_name)?; let buf_reader = BufReader::new(file); @@ -188,22 +189,19 @@ where return Err(msg); } match status.code() { - Some(code) => cert.debug(&format!("Hook {}: exited: code {}", hook.name, code)), - None => cert.debug(&format!("Hook {}: exited", hook.name)), + Some(code) => logger.debug(&format!("Hook {}: exited: code {}", hook.name, code)), + None => logger.debug(&format!("Hook {}: exited", hook.name)), }; Ok(()) } -pub fn call(cert: &Certificate, data: &T, hook_type: HookType) -> Result<(), Error> +pub fn call(logger: &L, hooks: &[Hook], data: &T, hook_type: HookType) -> Result<(), Error> where + L: HasLogger, T: Clone + HookEnvData + Serialize, { - for hook in cert - .hooks - .iter() - .filter(|h| h.hook_type.contains(&hook_type)) - { - call_single(cert, data, &hook).map_err(|e| e.prefix(&hook.name))?; + for hook in hooks.iter().filter(|h| h.hook_type.contains(&hook_type)) { + call_single(logger, data, &hook).map_err(|e| e.prefix(&hook.name))?; } Ok(()) } diff --git a/acmed/src/logs.rs b/acmed/src/logs.rs new file mode 100644 index 0000000..d32a313 --- /dev/null +++ b/acmed/src/logs.rs @@ -0,0 +1,6 @@ +pub trait HasLogger { + fn warn(&self, msg: &str); + fn info(&self, msg: &str); + fn debug(&self, msg: &str); + fn trace(&self, msg: &str); +} diff --git a/acmed/src/main.rs b/acmed/src/main.rs index 087f367..5e7b81b 100644 --- a/acmed/src/main.rs +++ b/acmed/src/main.rs @@ -15,6 +15,7 @@ mod hooks; mod http; mod identifier; mod jws; +mod logs; mod main_event_loop; mod storage; diff --git a/acmed/src/main_event_loop.rs b/acmed/src/main_event_loop.rs index 94d8084..eab3e7a 100644 --- a/acmed/src/main_event_loop.rs +++ b/acmed/src/main_event_loop.rs @@ -3,6 +3,9 @@ use crate::acme_proto::request_certificate; use crate::certificate::Certificate; use crate::config; use crate::endpoint::Endpoint; +use crate::hooks::HookType; +use crate::logs::HasLogger; +use crate::storage::FileManager; use acme_common::error::Error; use std::collections::HashMap; use std::sync::{Arc, RwLock}; @@ -38,33 +41,71 @@ pub struct MainEventLoop { impl MainEventLoop { pub fn new(config_file: &str, root_certs: &[&str]) -> Result { let cnf = config::from_file(config_file)?; + let file_hooks = vec![ + HookType::FilePreCreate, + HookType::FilePostCreate, + HookType::FilePreEdit, + HookType::FilePostEdit, + ] + .into_iter() + .collect(); + let cert_hooks = vec![ + HookType::ChallengeHttp01, + HookType::ChallengeHttp01Clean, + HookType::ChallengeDns01, + HookType::ChallengeDns01Clean, + HookType::ChallengeTlsAlpn01, + HookType::ChallengeTlsAlpn01Clean, + HookType::PostOperation, + ] + .into_iter() + .collect(); let mut certs = Vec::new(); let mut endpoints = HashMap::new(); for (i, crt) in cnf.certificate.iter().enumerate() { let endpoint = crt.get_endpoint(&cnf)?; let endpoint_name = endpoint.name.clone(); - let cert = Certificate { - account: crt.get_account(&cnf)?, - identifiers: crt.get_identifiers()?, - key_type: crt.get_key_type()?, - csr_digest: crt.get_csr_digest()?, - kp_reuse: crt.get_kp_reuse(), - endpoint_name: endpoint_name.clone(), - hooks: crt.get_hooks(&cnf)?, + let crt_name = crt.get_crt_name()?; + let key_type = crt.get_key_type()?; + let hooks = crt.get_hooks(&cnf)?; + let fm = FileManager { account_directory: cnf.get_account_dir(), - crt_directory: crt.get_crt_dir(&cnf), - crt_name: crt.get_crt_name()?, + account_name: crt.account.to_owned(), + crt_name: crt_name.clone(), crt_name_format: crt.get_crt_name_format(), + crt_directory: crt.get_crt_dir(&cnf), + crt_key_type: key_type.to_string(), cert_file_mode: cnf.get_cert_file_mode(), cert_file_owner: cnf.get_cert_file_user(), cert_file_group: cnf.get_cert_file_group(), pk_file_mode: cnf.get_pk_file_mode(), pk_file_owner: cnf.get_pk_file_user(), pk_file_group: cnf.get_pk_file_group(), + hooks: hooks + .iter() + .filter(|h| !h.hook_type.is_disjoint(&file_hooks)) + .map(|e| e.to_owned()) + .collect(), + env: crt.env.clone(), + }; + let cert = Certificate { + account: crt.get_account(&cnf, &fm)?, + identifiers: crt.get_identifiers()?, + key_type, + csr_digest: crt.get_csr_digest()?, + kp_reuse: crt.get_kp_reuse(), + endpoint_name: endpoint_name.clone(), + hooks: hooks + .iter() + .filter(|h| !h.hook_type.is_disjoint(&cert_hooks)) + .map(|e| e.to_owned()) + .collect(), + crt_name, env: crt.env.to_owned(), id: i + 1, renew_delay: crt.get_renew_delay(&cnf)?, + file_manager: fm, }; endpoints .entry(endpoint_name) diff --git a/acmed/src/storage.rs b/acmed/src/storage.rs index 8a89738..3d9512d 100644 --- a/acmed/src/storage.rs +++ b/acmed/src/storage.rs @@ -1,5 +1,5 @@ -use crate::certificate::Certificate; -use crate::hooks::{self, FileStorageHookData, HookEnvData, HookType}; +use crate::hooks::{self, FileStorageHookData, Hook, HookEnvData, HookType}; +use crate::logs::HasLogger; use acme_common::b64_encode; use acme_common::crypto::{KeyPair, X509Certificate}; use acme_common::error::Error; @@ -12,6 +12,42 @@ use std::path::PathBuf; #[cfg(target_family = "unix")] use std::os::unix::fs::OpenOptionsExt; +#[derive(Clone, Debug)] +pub struct FileManager { + pub account_name: String, + pub account_directory: String, + pub crt_name: String, + pub crt_name_format: String, + pub crt_directory: String, + pub crt_key_type: String, + pub cert_file_mode: u32, + pub cert_file_owner: Option, + pub cert_file_group: Option, + pub pk_file_mode: u32, + pub pk_file_owner: Option, + pub pk_file_group: Option, + pub hooks: Vec, + pub env: HashMap, +} + +impl HasLogger for FileManager { + fn warn(&self, msg: &str) { + log::warn!("{}: {}", &self.crt_name, msg); + } + + fn info(&self, msg: &str) { + log::info!("{}: {}", &self.crt_name, msg); + } + + fn debug(&self, msg: &str) { + log::debug!("{}: {}", &self.crt_name, msg); + } + + fn trace(&self, msg: &str) { + log::trace!("{}: {}", &self.crt_name, msg); + } +} + #[derive(Clone)] enum FileType { AccountPrivateKey, @@ -33,27 +69,27 @@ impl fmt::Display for FileType { } fn get_file_full_path( - cert: &Certificate, + fm: &FileManager, file_type: FileType, ) -> Result<(String, String, PathBuf), Error> { let base_path = match file_type { - FileType::AccountPrivateKey | FileType::AccountPublicKey => &cert.account_directory, - FileType::PrivateKey => &cert.crt_directory, - FileType::Certificate => &cert.crt_directory, + FileType::AccountPrivateKey | FileType::AccountPublicKey => &fm.account_directory, + FileType::PrivateKey => &fm.crt_directory, + FileType::Certificate => &fm.crt_directory, }; let file_name = match file_type { FileType::AccountPrivateKey | FileType::AccountPublicKey => format!( "{account}.{file_type}.{ext}", - account = b64_encode(&cert.account.name), + account = b64_encode(&fm.account_name), file_type = file_type.to_string(), ext = "pem" ), FileType::PrivateKey | FileType::Certificate => { - // TODO: use cert.crt_name_format instead of a string literal + // TODO: use fm.crt_name_format instead of a string literal format!( "{name}_{algo}.{file_type}.{ext}", - name = cert.crt_name, - algo = cert.key_type.to_string(), + name = fm.crt_name, + algo = fm.crt_key_type, file_type = file_type.to_string(), ext = "pem" ) @@ -64,13 +100,13 @@ fn get_file_full_path( Ok((base_path.to_string(), file_name, path)) } -fn get_file_path(cert: &Certificate, file_type: FileType) -> Result { - let (_, _, path) = get_file_full_path(cert, file_type)?; +fn get_file_path(fm: &FileManager, file_type: FileType) -> Result { + let (_, _, path) = get_file_full_path(fm, file_type)?; Ok(path) } -fn read_file(cert: &Certificate, path: &PathBuf) -> Result, Error> { - cert.trace(&format!("Reading file {:?}", path)); +fn read_file(fm: &FileManager, path: &PathBuf) -> Result, Error> { + fm.trace(&format!("Reading file {:?}", path)); let mut file = File::open(path)?; let mut contents = vec![]; file.read_to_end(&mut contents)?; @@ -78,15 +114,12 @@ fn read_file(cert: &Certificate, path: &PathBuf) -> Result, Error> { } #[cfg(unix)] -fn set_owner(cert: &Certificate, path: &PathBuf, file_type: FileType) -> Result<(), Error> { +fn set_owner(fm: &FileManager, path: &PathBuf, file_type: FileType) -> Result<(), Error> { let (uid, gid) = match file_type { - FileType::Certificate => ( - cert.cert_file_owner.to_owned(), - cert.cert_file_group.to_owned(), - ), - FileType::PrivateKey => (cert.pk_file_owner.to_owned(), cert.pk_file_group.to_owned()), + FileType::Certificate => (fm.cert_file_owner.to_owned(), fm.cert_file_group.to_owned()), + FileType::PrivateKey => (fm.pk_file_owner.to_owned(), fm.pk_file_group.to_owned()), FileType::AccountPrivateKey | FileType::AccountPublicKey => { - // The account private and public keys does not need to be accessible to users other different from the current one. + // The account file does not need to be accessible to users other different from the current one. return Ok(()); } }; @@ -121,12 +154,12 @@ fn set_owner(cert: &Certificate, path: &PathBuf, file_type: FileType) -> Result< None => None, }; match uid { - Some(u) => cert.trace(&format!("{:?}: setting the uid to {}", path, u.as_raw())), - None => cert.trace(&format!("{:?}: uid unchanged", path)), + Some(u) => fm.trace(&format!("{:?}: setting the uid to {}", path, u.as_raw())), + None => fm.trace(&format!("{:?}: uid unchanged", path)), }; match gid { - Some(g) => cert.trace(&format!("{:?}: setting the gid to {}", path, g.as_raw())), - None => cert.trace(&format!("{:?}: gid unchanged", path)), + Some(g) => fm.trace(&format!("{:?}: setting the gid to {}", path, g.as_raw())), + None => fm.trace(&format!("{:?}: gid unchanged", path)), }; match nix::unistd::chown(path, uid, gid) { Ok(_) => Ok(()), @@ -134,29 +167,29 @@ fn set_owner(cert: &Certificate, path: &PathBuf, file_type: FileType) -> Result< } } -fn write_file(cert: &Certificate, file_type: FileType, data: &[u8]) -> Result<(), Error> { - let (file_directory, file_name, path) = get_file_full_path(cert, file_type.clone())?; +fn write_file(fm: &FileManager, file_type: FileType, data: &[u8]) -> Result<(), Error> { + let (file_directory, file_name, path) = get_file_full_path(fm, file_type.clone())?; let mut hook_data = FileStorageHookData { file_name, file_directory, file_path: path.to_owned(), env: HashMap::new(), }; - hook_data.set_env(&cert.env); + hook_data.set_env(&fm.env); let is_new = !path.is_file(); if is_new { - hooks::call(cert, &hook_data, HookType::FilePreCreate)?; + hooks::call(fm, &fm.hooks, &hook_data, HookType::FilePreCreate)?; } else { - hooks::call(cert, &hook_data, HookType::FilePreEdit)?; + hooks::call(fm, &fm.hooks, &hook_data, HookType::FilePreEdit)?; } - cert.trace(&format!("Writing file {:?}", path)); + fm.trace(&format!("Writing file {:?}", path)); let mut file = if cfg!(unix) { let mut options = OpenOptions::new(); options.mode(match &file_type { - FileType::Certificate => cert.cert_file_mode, - FileType::PrivateKey => cert.pk_file_mode, + FileType::Certificate => fm.cert_file_mode, + FileType::PrivateKey => fm.pk_file_mode, FileType::AccountPublicKey => crate::DEFAULT_ACCOUNT_FILE_MODE, FileType::AccountPrivateKey => crate::DEFAULT_ACCOUNT_FILE_MODE, }); @@ -166,64 +199,64 @@ fn write_file(cert: &Certificate, file_type: FileType, data: &[u8]) -> Result<() }; file.write_all(data)?; if cfg!(unix) { - set_owner(cert, &path, file_type)?; + set_owner(fm, &path, file_type)?; } if is_new { - hooks::call(cert, &hook_data, HookType::FilePostCreate)?; + hooks::call(fm, &fm.hooks, &hook_data, HookType::FilePostCreate)?; } else { - hooks::call(cert, &hook_data, HookType::FilePostEdit)?; + hooks::call(fm, &fm.hooks, &hook_data, HookType::FilePostEdit)?; } Ok(()) } -pub fn get_account_keypair(cert: &Certificate) -> Result { - let path = get_file_path(cert, FileType::AccountPrivateKey)?; - let raw_key = read_file(cert, &path)?; +pub fn get_account_keypair(fm: &FileManager) -> Result { + let path = get_file_path(fm, FileType::AccountPrivateKey)?; + let raw_key = read_file(fm, &path)?; let key = KeyPair::from_pem(&raw_key)?; Ok(key) } -pub fn set_account_keypair(cert: &Certificate, key_pair: &KeyPair) -> Result<(), Error> { +pub fn set_account_keypair(fm: &FileManager, key_pair: &KeyPair) -> Result<(), Error> { let pem_pub_key = key_pair.private_key_to_pem()?; let pem_priv_key = key_pair.public_key_to_pem()?; - write_file(cert, FileType::AccountPublicKey, &pem_priv_key)?; - write_file(cert, FileType::AccountPrivateKey, &pem_pub_key)?; + write_file(fm, FileType::AccountPublicKey, &pem_priv_key)?; + write_file(fm, FileType::AccountPrivateKey, &pem_pub_key)?; Ok(()) } -pub fn get_keypair(cert: &Certificate) -> Result { - let path = get_file_path(cert, FileType::PrivateKey)?; - let raw_key = read_file(cert, &path)?; +pub fn get_keypair(fm: &FileManager) -> Result { + let path = get_file_path(fm, FileType::PrivateKey)?; + let raw_key = read_file(fm, &path)?; let key = KeyPair::from_pem(&raw_key)?; Ok(key) } -pub fn set_keypair(cert: &Certificate, key_pair: &KeyPair) -> Result<(), Error> { +pub fn set_keypair(fm: &FileManager, key_pair: &KeyPair) -> Result<(), Error> { let data = key_pair.private_key_to_pem()?; - write_file(cert, FileType::PrivateKey, &data) + write_file(fm, FileType::PrivateKey, &data) } -pub fn get_certificate(cert: &Certificate) -> Result { - let path = get_file_path(cert, FileType::Certificate)?; - let raw_crt = read_file(cert, &path)?; +pub fn get_certificate(fm: &FileManager) -> Result { + let path = get_file_path(fm, FileType::Certificate)?; + let raw_crt = read_file(fm, &path)?; let crt = X509Certificate::from_pem(&raw_crt)?; Ok(crt) } -pub fn write_certificate(cert: &Certificate, data: &[u8]) -> Result<(), Error> { - write_file(cert, FileType::Certificate, data) +pub fn write_certificate(fm: &FileManager, data: &[u8]) -> Result<(), Error> { + write_file(fm, FileType::Certificate, data) } -fn check_files(cert: &Certificate, file_types: &[FileType]) -> bool { +fn check_files(fm: &FileManager, file_types: &[FileType]) -> bool { for t in file_types.to_vec() { - let path = match get_file_path(cert, t) { + let path = match get_file_path(fm, t) { Ok(p) => p, Err(_) => { return false; } }; - cert.trace(&format!( + fm.trace(&format!( "Testing file path: {}", path.to_str().unwrap_or_default() )); @@ -234,12 +267,12 @@ fn check_files(cert: &Certificate, file_types: &[FileType]) -> bool { true } -pub fn account_files_exists(cert: &Certificate) -> bool { +pub fn account_files_exists(fm: &FileManager) -> bool { let file_types = vec![FileType::AccountPrivateKey, FileType::AccountPublicKey]; - check_files(cert, &file_types) + check_files(fm, &file_types) } -pub fn certificate_files_exists(cert: &Certificate) -> bool { +pub fn certificate_files_exists(fm: &FileManager) -> bool { let file_types = vec![FileType::PrivateKey, FileType::Certificate]; - check_files(cert, &file_types) + check_files(fm, &file_types) }