mod containers_parsing;
mod decode;
mod descriptors;
pub mod types;
pub use types::{
ArtifactDescriptor, ArtifactParsingProfile, ArtifactQuery, ArtifactRecord, ArtifactType,
ArtifactValue, BinaryField, BinaryFieldType, ContainerProfile, ContainerSignature, DataScope,
DecodeError, Decoder, FieldSchema, ForensicCatalog, HiveTarget, OsScope, Platform,
PlatformMask, RecordSignature, TriagePriority, ValueType,
};
pub use containers_parsing::{
all_container_profiles, all_container_signatures, all_parsing_profiles, all_record_signatures,
container_profile, container_signature, parsing_profile, record_signatures_for_container,
};
pub fn container_profile_for_artifact(id: &str) -> Option<&'static ContainerProfile> {
use containers_parsing::artifact_container_bindings;
if let Some(binding) = artifact_container_bindings()
.iter()
.find(|b| b.artifact_id.eq_ignore_ascii_case(id))
{
return container_profile(binding.container_id);
}
let desc = CATALOG.by_id(id)?;
containers_parsing::infer_container_profile_pub(desc)
}
pub fn container_signature_for_artifact(id: &str) -> Option<&'static ContainerSignature> {
let profile = container_profile_for_artifact(id)?;
container_signature(profile.id)
}
pub fn record_signatures_for_artifact(id: &str) -> Vec<&'static RecordSignature> {
let direct: Vec<&'static RecordSignature> = all_record_signatures()
.iter()
.filter(|sig| {
sig.artifact_id
.is_some_and(|artifact_id| artifact_id.eq_ignore_ascii_case(id))
})
.collect();
if !direct.is_empty() {
return direct;
}
if let Some(container_sig) = container_profile_for_artifact(id) {
return record_signatures_for_container(container_sig.id);
}
Vec::new()
}
impl ForensicCatalog {
pub fn parsing_profile(&self, id: &str) -> Option<&'static ArtifactParsingProfile> {
parsing_profile(id)
}
pub fn container_profile(&self, id: &str) -> Option<&'static ContainerProfile> {
container_profile_for_artifact(id)
}
pub fn container_signature(&self, id: &str) -> Option<&'static ContainerSignature> {
container_signature_for_artifact(id)
}
pub fn record_signatures(&self, id: &str) -> Vec<&'static RecordSignature> {
record_signatures_for_artifact(id)
}
pub fn decode(
&self,
descriptor: &ArtifactDescriptor,
name: &str,
raw: &[u8],
) -> Result<ArtifactRecord, DecodeError> {
decode::decode_artifact(descriptor, name, raw)
}
}
#[cfg(test)]
#[doc(hidden)]
pub(crate) use decode::{filetime_to_iso8601, rot13};
#[cfg(test)]
#[doc(hidden)]
pub(crate) use descriptors::*;
pub static CATALOG: ForensicCatalog = ForensicCatalog::new(descriptors::CATALOG_ENTRIES);
#[cfg(test)]
mod tests;
#[cfg(test)]
mod refactor_contract {
use super::*;
#[test]
fn catalog_api_surface_intact() {
let _ = CATALOG.by_id("userassist_exe");
let _ = CATALOG.for_triage();
let _ = CATALOG.by_mitre("T1547.001");
let _ = CATALOG.filter_by_keyword("prefetch");
let _: ArtifactType = ArtifactType::File;
let _: TriagePriority = TriagePriority::Critical;
let _: DataScope = DataScope::User;
let _: OsScope = OsScope::Win10Plus;
let _: HiveTarget = HiveTarget::NtUser;
let _ = all_container_profiles();
let _ = all_container_signatures();
let _ = all_parsing_profiles();
let _ = all_record_signatures();
}
}