use std::sync::Arc;
use crate::cache::{CustomCache, DEKCache, MokaCache};
#[cfg(feature = "aws")]
use crate::cmk::AwsCMK;
#[cfg(feature = "azure")]
use crate::cmk::AzureCMK;
use crate::cmk::{CustomCMK, CMK};
use crate::dek::generator::key_generator::custom::CustomGenerator;
use crate::dek::generator::key_generator::fixed::FixedLengthGenerator;
#[cfg(feature = "debug")]
use crate::dek::generator::key_generator::string::StringGenerator;
use crate::dek::generator::DEKGenerator;
#[cfg(feature = "aws")]
use crate::dek::persistence::AWSPersister;
#[cfg(feature = "azure")]
use crate::dek::persistence::AzurePersister;
#[cfg(feature = "debug")]
use crate::dek::persistence::MemPersister;
use crate::dek::persistence::{CustomPersister, DEKPersistService, DEKPersister};
use crate::encryption::EncryptionStrategy;
use crate::error::cache::CacheError;
use crate::error::cmk::CMKError;
use crate::error::generator::{GenerateKeyError, PersistError};
use crate::HYOKService;
#[cfg(feature = "aws")]
use aws_sdk_kms::types::EncryptionAlgorithmSpec;
#[cfg(feature = "azure")]
use azure_security_keyvault::prelude::CryptographParamtersEncryption;
use std::time::Duration;
pub enum GeneratorConfig {
FixedLength(usize),
#[cfg(feature = "debug")]
String(String),
Custom {
generate_fn: Arc<dyn (Fn() -> Result<Vec<u8>, GenerateKeyError>) + Send + Sync>,
},
}
pub enum CacheConfig {
NoCache,
Custom {
get_fn: Arc<dyn (Fn(&String) -> Option<Vec<u8>>) + Send + Sync>,
set_fn: Arc<dyn (Fn(String, Vec<u8>) -> Result<Vec<u8>, CacheError>) + Send + Sync>,
},
Moka {
cache_size: u64,
time_to_live: Duration,
time_to_idle: Duration,
},
}
pub enum PersisterConfig {
#[cfg(feature = "aws")]
Aws {
client: aws_sdk_secretsmanager::Client,
},
#[cfg(feature = "azure")]
Azure {
client: azure_security_keyvault::KeyvaultClient,
},
#[cfg(feature = "debug")]
Memory,
Custom {
persist_fn: Arc<
dyn (Fn(
Vec<u8>,
String
) -> futures::future::BoxFuture<'static, Result<Vec<u8>, PersistError>>) +
Send +
Sync
>,
fetch_fn: Arc<
dyn (Fn(String) -> futures::future::BoxFuture<'static, Result<Vec<u8>, PersistError>>) +
Send +
Sync
>,
},
}
pub enum CMKConfig {
#[cfg(feature = "aws")]
Aws {
client: aws_sdk_kms::Client,
key_name: String,
algorithm: EncryptionAlgorithmSpec,
},
#[cfg(feature = "azure")]
Azure {
client: azure_security_keyvault::KeyvaultClient,
key_name: String,
params: CryptographParamtersEncryption,
},
Custom {
encrypt_fn: Arc<
dyn (Fn(Vec<u8>) -> futures::future::BoxFuture<'static, Result<Vec<u8>, CMKError>>) +
Send +
Sync
>,
decrypt_fn: Arc<
dyn (Fn(Vec<u8>) -> futures::future::BoxFuture<'static, Result<Vec<u8>, CMKError>>) +
Send +
Sync
>,
},
}
pub struct HYOKServiceBuilder {
persist_config: Option<PersisterConfig>,
cmk_config: Option<CMKConfig>,
cache_config: Option<CacheConfig>,
generator_config: Option<GeneratorConfig>,
}
impl Default for HYOKServiceBuilder {
fn default() -> Self {
Self {
cmk_config: None,
cache_config: Some(CacheConfig::Moka {
cache_size: 10000,
time_to_live: Duration::from_secs(300),
time_to_idle: Duration::from_secs(120),
}),
generator_config: Some(GeneratorConfig::FixedLength(32)),
persist_config: None,
}
}
}
impl HYOKServiceBuilder {
pub fn new() -> Self {
Self {
cmk_config: None,
cache_config: None,
persist_config: None,
generator_config: None,
}
}
#[cfg(feature = "aws")]
pub fn with_aws_cmk(
mut self,
client: aws_sdk_kms::Client,
key_name: impl Into<String>,
algorithm: EncryptionAlgorithmSpec
) -> Self {
self.cmk_config = Some(CMKConfig::Aws {
client,
key_name: key_name.into(),
algorithm,
});
self
}
#[cfg(feature = "azure")]
pub fn with_azure_cmk(
mut self,
key_name: impl Into<String>,
params: CryptographParamtersEncryption,
client: azure_security_keyvault::KeyvaultClient
) -> Self {
self.cmk_config = Some(CMKConfig::Azure {
client,
key_name: key_name.into(),
params,
});
self
}
pub fn with_custom_cmk<E, D>(mut self, encrypt_fn: E, decrypt_fn: D) -> Self
where
E: Fn(Vec<u8>) -> futures::future::BoxFuture<'static, Result<Vec<u8>, CMKError>> +
Send +
Sync +
'static,
D: Fn(Vec<u8>) -> futures::future::BoxFuture<'static, Result<Vec<u8>, CMKError>> +
Send +
Sync +
'static
{
self.cmk_config = Some(CMKConfig::Custom {
encrypt_fn: Arc::new(encrypt_fn),
decrypt_fn: Arc::new(decrypt_fn),
});
self
}
pub fn with_moka_cache(
mut self,
cache_size: u64,
time_to_live: Duration,
time_to_idle: Duration
) -> Self {
self.cache_config = Some(CacheConfig::Moka {
cache_size,
time_to_live,
time_to_idle,
});
self
}
pub fn with_custom_cache<G, S>(mut self, get_fn: G, set_fn: S) -> Self
where
G: Fn(&String) -> Option<Vec<u8>> + Send + Sync + 'static,
S: Fn(String, Vec<u8>) -> Result<Vec<u8>, CacheError> + Send + Sync + 'static
{
self.cache_config = Some(CacheConfig::Custom {
get_fn: Arc::new(get_fn),
set_fn: Arc::new(set_fn),
});
self
}
pub fn with_no_cache(mut self) -> Self {
self.cache_config = Some(CacheConfig::NoCache);
self
}
pub fn with_fixed_length_generator(mut self, key_length: usize) -> Self {
self.generator_config = Some(GeneratorConfig::FixedLength(key_length));
self
}
#[cfg(feature = "debug")]
pub fn with_string_generator(mut self, key: String) -> Self {
self.generator_config = Some(GeneratorConfig::String(key));
self
}
pub fn with_custom_generator<G>(mut self, generate_fn: G) -> Self
where G: Fn() -> Result<Vec<u8>, GenerateKeyError> + Send + Sync + 'static
{
self.generator_config = Some(GeneratorConfig::Custom {
generate_fn: Arc::new(generate_fn),
});
self
}
#[cfg(feature = "azure")]
pub fn with_azure_persistence(
mut self,
client: azure_security_keyvault::KeyvaultClient
) -> Self {
self.persist_config = Some(PersisterConfig::Azure {
client,
});
self
}
#[cfg(feature = "aws")]
pub fn with_aws_persistence(mut self, client: aws_sdk_secretsmanager::Client) -> Self {
self.persist_config = Some(PersisterConfig::Aws {
client,
});
self
}
#[cfg(feature = "debug")]
pub fn with_memory_persistence(mut self) -> Self {
self.persist_config = Some(PersisterConfig::Memory);
self
}
pub fn with_custom_persistence<P, F>(mut self, persist_fn: P, fetch_fn: F) -> Self
where
P: Fn(
Vec<u8>,
String
) -> futures::future::BoxFuture<'static, Result<Vec<u8>, PersistError>> +
Send +
Sync +
'static,
F: Fn(String) -> futures::future::BoxFuture<'static, Result<Vec<u8>, PersistError>> +
Send +
Sync +
'static
{
self.persist_config = Some(PersisterConfig::Custom {
persist_fn: Arc::new(persist_fn),
fetch_fn: Arc::new(fetch_fn),
});
self
}
pub fn build<S: EncryptionStrategy<EncryptionData = ED> + Send + Sync, ED: Send>(
self,
strategy: S
) -> Result<HYOKService<S>, String> {
let generator = match self.generator_config.ok_or("Generator config required")? {
GeneratorConfig::FixedLength(length) =>
DEKGenerator::Fixed(FixedLengthGenerator::new(length)),
#[cfg(feature = "debug")]
GeneratorConfig::String(length) => DEKGenerator::String(StringGenerator::new(length)),
GeneratorConfig::Custom { generate_fn } =>
DEKGenerator::Custom(CustomGenerator::new(move || generate_fn())),
};
let cmk = match self.cmk_config.ok_or("CMK config required")? {
#[cfg(feature = "aws")]
CMKConfig::Aws { client, key_name, algorithm } => {
CMK::AWS(AwsCMK::new(Arc::new(client), key_name, algorithm))
}
#[cfg(feature = "azure")]
CMKConfig::Azure { client, key_name, params } => {
CMK::Azure(AzureCMK::new(Arc::new(client), key_name, params))
}
CMKConfig::Custom { encrypt_fn, decrypt_fn } => {
CMK::Custom(
CustomCMK::new(
move |key| encrypt_fn(key),
move |key| decrypt_fn(key)
)
)
}
};
let cache = match self.cache_config.ok_or("Cache config required")? {
CacheConfig::NoCache => DEKCache::NoCache,
CacheConfig::Custom { get_fn, set_fn } => {
DEKCache::Custom(
CustomCache::new(
move |key| get_fn(key),
move |key, value| set_fn(key, value)
)
)
}
CacheConfig::Moka { cache_size, time_to_live, time_to_idle } => {
DEKCache::Moka(MokaCache::new(cache_size, time_to_live, time_to_idle))
}
};
let persister = match self.persist_config.ok_or("Persister config required")? {
#[cfg(feature = "aws")]
PersisterConfig::Aws { client } =>
DEKPersister::AWS(AWSPersister::new(Arc::new(client))),
#[cfg(feature = "azure")]
PersisterConfig::Azure { client } =>
DEKPersister::Azure(AzurePersister::new(Arc::new(client))),
#[cfg(feature = "debug")]
PersisterConfig::Memory => DEKPersister::Mem(MemPersister::new()),
PersisterConfig::Custom { persist_fn, fetch_fn } => {
DEKPersister::Custom(
CustomPersister::new(
move |key, context| persist_fn(key, context),
move |context| fetch_fn(context)
)
)
}
};
let persist_service = DEKPersistService::new(
Arc::new(persister),
Arc::new(cmk),
Some(Arc::new(cache))
);
Ok(HYOKService::new(Arc::new(persist_service), generator, strategy))
}
}