use crate::storage::repositories::db_metadata_repository::DBMetadataRepository;
use crate::storage::repositories::filter_includes_repository::FilterIncludesRepository;
use crate::storage::repositories::filter_repository::FilterRepository;
use crate::storage::repositories::rules_list_repository::RulesListRepository;
use crate::storage::with_transaction;
use crate::storage::DbConnectionManager;
use crate::utils::integrity;
use crate::{Configuration, FLMError, FLMResult};
use rusqlite::{Connection, Transaction};
pub(crate) struct IntegrityControlManager;
impl IntegrityControlManager {
pub(crate) const fn new() -> Self {
Self {}
}
pub(crate) fn sign_all_data(
&self,
connection_manager: &DbConnectionManager,
configuration: &Configuration,
) -> FLMResult<()> {
let integrity_key =
configuration
.integrity_key
.as_deref()
.ok_or(FLMError::InvalidConfiguration(
"integrity_key is required for sign_all_data",
))?;
let derived_key = integrity::derive_key(integrity_key);
connection_manager.execute_db(|mut conn: Connection| {
let rules_list_repository = RulesListRepository::new();
let filter_includes_repository = FilterIncludesRepository::new();
let filter_repository = FilterRepository::new();
let rules_signatures = rules_list_repository
.sign_and_collect_signatures_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?;
let includes_signatures = filter_includes_repository
.sign_and_collect_signatures_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?;
let metadata_signatures = filter_repository
.sign_and_collect_metadata_signatures_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?;
let count = filter_repository
.count_all(&conn)
.map_err(FLMError::from_database)?;
let count_signature = integrity::sign_filter_count(&derived_key, count);
with_transaction(&mut conn, |tx: &Transaction| {
rules_list_repository.batch_update_signatures(tx, &rules_signatures)?;
filter_includes_repository.batch_update_signatures(tx, &includes_signatures)?;
filter_repository.batch_update_metadata_signatures(tx, &metadata_signatures)?;
let mut meta = DBMetadataRepository::read(tx)?.unwrap_or_default();
meta.filter_count_signature = Some(count_signature);
DBMetadataRepository::save(tx, &meta)
})
})
}
pub(crate) fn verify_integrity(
&self,
connection_manager: &DbConnectionManager,
configuration: &Configuration,
) -> FLMResult<()> {
let integrity_key =
configuration
.integrity_key
.as_deref()
.ok_or(FLMError::InvalidConfiguration(
"integrity_key is required for verify_integrity",
))?;
let derived_key = integrity::derive_key(integrity_key);
connection_manager.execute_db(|conn: Connection| {
let filter_repository = FilterRepository::new();
if let Some(filter_id) = RulesListRepository::new()
.verify_all_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?
{
return Err(FLMError::FilterIntegrityCheckFailed(filter_id));
}
if let Some(filter_id) = FilterIncludesRepository::new()
.verify_all_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?
{
return Err(FLMError::FilterIntegrityCheckFailed(filter_id));
}
if let Some(filter_id) = filter_repository
.verify_all_metadata_streaming(&conn, &derived_key)
.map_err(FLMError::from_database)?
{
return Err(FLMError::FilterIntegrityCheckFailed(filter_id));
}
let meta = DBMetadataRepository::read(&conn)
.map_err(FLMError::from_database)?
.unwrap_or_default();
let current_count = filter_repository
.count_all(&conn)
.map_err(FLMError::from_database)?;
match meta.filter_count_signature {
Some(ref stored_sig) => {
if !integrity::verify_filter_count(&derived_key, current_count, stored_sig) {
return Err(FLMError::FilterIntegrityCheckFailed(0));
}
}
None => {
return Err(FLMError::FilterIntegrityCheckFailed(0));
}
}
Ok(())
})
}
}