mod database_objects;
mod database_permissions;
use std::{collections::HashMap, sync::Arc, time::Duration};
#[cfg(feature = "non-fips")]
use cosmian_kms_crypto::reexport::cosmian_crypto_core::Secret;
use cosmian_kms_interfaces::{ObjectsStore, PermissionsStore};
use tokio::sync::RwLock;
use crate::error::DbResult;
mod main_db_params;
pub use main_db_params::{AdditionalObjectStoresParams, MainDbParams};
mod unwrapped_cache;
pub use crate::core::unwrapped_cache::{CachedUnwrappedObject, UnwrappedCache};
#[cfg(feature = "non-fips")]
use crate::stores::RedisWithFindex;
use crate::stores::{MySqlPool, PgPool, SqlitePool};
pub struct Database {
objects: RwLock<HashMap<String, Arc<dyn ObjectsStore + Sync + Send>>>,
permissions: Arc<dyn PermissionsStore + Sync + Send>,
unwrapped_cache: UnwrappedCache,
}
impl Database {
pub async fn instantiate(
main_db_params: &MainDbParams,
clear_db_on_start: bool,
object_stores: HashMap<String, Arc<dyn ObjectsStore + Sync + Send>>,
cache_max_age: Duration,
) -> DbResult<Self> {
let db = Self::instantiate_main_database(main_db_params, clear_db_on_start, cache_max_age)
.await?;
for (prefix, store) in object_stores {
db.register_objects_store(&prefix, store).await;
}
Ok(db)
}
async fn instantiate_main_database(
main_db_params: &MainDbParams,
clear_db_on_start: bool,
cache_max_age: Duration,
) -> DbResult<Self> {
Ok(match main_db_params {
MainDbParams::Sqlite(db_path) => {
let db = Arc::new(
SqlitePool::instantiate(&db_path.join("kms.db"), clear_db_on_start).await?,
);
Self::new(db.clone(), db, cache_max_age)
}
MainDbParams::Postgres(url) => {
let db = Arc::new(PgPool::instantiate(url.as_str(), clear_db_on_start).await?);
Self::new(db.clone(), db, cache_max_age)
}
MainDbParams::Mysql(url) => {
let db = Arc::new(MySqlPool::instantiate(url.as_str(), clear_db_on_start).await?);
Self::new(db.clone(), db, cache_max_age)
}
#[cfg(feature = "non-fips")]
MainDbParams::RedisFindex(url, master_key, label) => {
use cosmian_kms_crypto::reexport::cosmian_crypto_core::FixedSizeCBytes;
use crate::stores::REDIS_WITH_FINDEX_MASTER_KEY_LENGTH;
let new_master_key =
Secret::<REDIS_WITH_FINDEX_MASTER_KEY_LENGTH>::from_unprotected_bytes(
&mut master_key.to_bytes(),
);
let db = Arc::new(
RedisWithFindex::instantiate(
url.as_str(),
new_master_key,
clear_db_on_start,
label.as_deref(),
)
.await?,
);
Self::new(db.clone(), db, cache_max_age)
}
})
}
pub const fn unwrapped_cache(&self) -> &UnwrappedCache {
&self.unwrapped_cache
}
pub(crate) fn new(
default_objects_database: Arc<dyn ObjectsStore + Sync + Send>,
permissions_database: Arc<dyn PermissionsStore + Sync + Send>,
cache_max_age: Duration,
) -> Self {
Self {
objects: RwLock::new(HashMap::from([(String::new(), default_objects_database)])),
permissions: permissions_database,
unwrapped_cache: UnwrappedCache::new(cache_max_age),
}
}
}