Browse Source

Create a dedicated FileManager struct

The certificate struct was bloated with file management data which
therefore required the certificate to be passed in every storage
function. In order to clean this, a new FileManager struct has been
created.
pull/39/head
Rodolphe Breard 4 years ago
parent
commit
69739d4703
  1. 2
      acmed/src/account.rs
  2. 3
      acmed/src/acme_proto.rs
  3. 11
      acmed/src/acme_proto/account.rs
  4. 4
      acmed/src/acme_proto/certificate.rs
  5. 35
      acmed/src/certificate.rs
  6. 16
      acmed/src/config.rs
  7. 42
      acmed/src/hooks.rs
  8. 6
      acmed/src/logs.rs
  9. 1
      acmed/src/main.rs
  10. 61
      acmed/src/main_event_loop.rs
  11. 151
      acmed/src/storage.rs

2
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<String>,

3
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: {})",

11
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<Self, Error> {
// 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

4
acmed/src/acme_proto/certificate.rs

@ -5,12 +5,12 @@ use acme_common::error::Error;
fn gen_key_pair(cert: &Certificate) -> Result<KeyPair, Error> {
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<KeyPair, Error> {
storage::get_keypair(cert)
storage::get_keypair(&cert.file_manager)
}
pub fn get_key_pair(cert: &Certificate) -> Result<KeyPair, Error> {

35
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<Hook>,
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<String>,
pub cert_file_group: Option<String>,
pub pk_file_mode: u32,
pub pk_file_owner: Option<String>,
pub pk_file_group: Option<String>,
pub env: HashMap<String, String>,
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<Identifier, Error> {
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(())
}
}

16
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<bool>,
}
#[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<crate::account::Account, Error> {
pub fn to_generic(&self, file_manager: &FileManager) -> Result<crate::account::Account, Error> {
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<crate::account::Account, Error> {
pub fn get_account(
&self,
cnf: &Config,
file_manager: &FileManager,
) -> Result<crate::account::Account, Error> {
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);
}
}

42
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<HookType>,
pub hook_type: HashSet<HookType>,
pub cmd: String,
pub args: Option<Vec<String>>,
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<T>(cert: &Certificate, data: &T, hook: &Hook) -> Result<(), Error>
fn call_single<L, T>(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<T>(cert: &Certificate, data: &T, hook_type: HookType) -> Result<(), Error>
pub fn call<L, T>(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(())
}

6
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);
}

1
acmed/src/main.rs

@ -15,6 +15,7 @@ mod hooks;
mod http;
mod identifier;
mod jws;
mod logs;
mod main_event_loop;
mod storage;

61
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<Self, Error> {
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)

151
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<String>,
pub cert_file_group: Option<String>,
pub pk_file_mode: u32,
pub pk_file_owner: Option<String>,
pub pk_file_group: Option<String>,
pub hooks: Vec<Hook>,
pub env: HashMap<String, String>,
}
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<PathBuf, Error> {
let (_, _, path) = get_file_full_path(cert, file_type)?;
fn get_file_path(fm: &FileManager, file_type: FileType) -> Result<PathBuf, Error> {
let (_, _, path) = get_file_full_path(fm, file_type)?;
Ok(path)
}
fn read_file(cert: &Certificate, path: &PathBuf) -> Result<Vec<u8>, Error> {
cert.trace(&format!("Reading file {:?}", path));
fn read_file(fm: &FileManager, path: &PathBuf) -> Result<Vec<u8>, 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<Vec<u8>, 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<KeyPair, Error> {
let path = get_file_path(cert, FileType::AccountPrivateKey)?;
let raw_key = read_file(cert, &path)?;
pub fn get_account_keypair(fm: &FileManager) -> Result<KeyPair, Error> {
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<KeyPair, Error> {
let path = get_file_path(cert, FileType::PrivateKey)?;
let raw_key = read_file(cert, &path)?;
pub fn get_keypair(fm: &FileManager) -> Result<KeyPair, Error> {
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<X509Certificate, Error> {
let path = get_file_path(cert, FileType::Certificate)?;
let raw_crt = read_file(cert, &path)?;
pub fn get_certificate(fm: &FileManager) -> Result<X509Certificate, Error> {
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)
}
Loading…
Cancel
Save