use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Serialize, Deserialize};
use serde_with::{SerializeDisplay, DeserializeFromStr};
use struct_metadata::Described;
use crate::{Sha256, ElasticMeta, ClassificationString, ExpandingClassification};
use super::tagging::Tagging;
#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum BodyFormat {
Text,
MemoryDump,
GraphData,
Url,
Json,
KeyValue,
ProcessTree,
Table,
Image,
Multi,
OrderedKeyValue,
Timeline,
}
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct Attack {
#[metadata(copyto="__text__")]
pub attack_id: String,
#[metadata(copyto="__text__")]
pub pattern: String,
pub categories: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct Signature {
#[metadata(copyto="__text__")]
pub name: String,
#[serde(default = "default_signature_frequency")]
pub frequency: i64,
#[serde(default)]
pub safe: bool,
}
fn default_signature_frequency() -> i64 { 1 }
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct Heuristic {
#[metadata(copyto="__text__")]
pub heur_id: String,
#[metadata(copyto="__text__")]
pub name: String,
#[serde(default)]
pub attack: Vec<Attack>,
#[serde(default)]
pub signature: Vec<Signature>,
pub score: i64,
}
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct Section {
#[serde(default)]
pub auto_collapse: bool,
#[metadata(copyto="__text__")]
pub body: Option<String>,
pub classification: ClassificationString,
#[metadata(index=false)]
pub body_format: BodyFormat,
#[metadata(index=false)]
pub body_config: Option<HashMap<String, serde_json::Value>>,
#[metadata(index=false)]
pub depth: i64,
pub heuristic: Option<Heuristic>,
#[serde(default)]
pub tags: Box<Tagging>,
#[serde(default)]
#[metadata(store=false)]
pub safelisted_tags: HashMap<String, Vec<serde_json::Value>>,
#[metadata(copyto="__text__")]
pub title_text: String,
}
#[derive(Serialize, Deserialize, Debug, Default, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=false, store=false)]
pub struct ResultBody {
#[serde(default)]
pub score: i64,
#[serde(default)]
pub sections: Vec<Section>,
}
#[derive(Serialize, Deserialize, Debug, Default, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=false, store=false)]
pub struct Milestone {
pub service_started: DateTime<Utc>,
pub service_completed: DateTime<Utc>,
}
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct File {
#[metadata(copyto="__text__")]
pub name: String,
#[metadata(copyto="__text__")]
pub sha256: Sha256,
#[metadata(copyto="__text__")]
pub description: String,
pub classification: ClassificationString,
#[serde(default)]
pub is_section_image: bool,
#[serde(default = "default_file_parent_relation")]
pub parent_relation: String,
#[serde(default)]
pub allow_dynamic_recursion: bool,
}
fn default_file_parent_relation() -> String { "EXTRACTED".to_owned() }
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=true)]
pub struct ResponseBody {
#[serde(default)]
pub milestones: Milestone,
#[metadata(store=false)]
pub service_version: String,
#[metadata(copyto="__text__")]
pub service_name: String,
#[metadata(copyto="__text__")]
pub service_tool_version: Option<String>,
#[serde(default)]
pub supplementary: Vec<File>,
#[serde(default)]
pub extracted: Vec<File>,
#[metadata(index=false, store=false)]
pub service_context: Option<String>,
#[metadata(index=false, store=false)]
pub service_debug_info: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=true)]
pub struct Result {
#[serde(flatten)]
pub classification: ExpandingClassification,
pub created: DateTime<Utc>,
#[metadata(store=false)]
pub expiry_ts: Option<DateTime<Utc>>,
pub response: ResponseBody,
#[serde(default)]
pub result: ResultBody,
#[metadata(store=false)]
pub sha256: Sha256,
#[serde(rename = "type")]
pub result_type: Option<String>,
pub size: Option<u64>,
#[serde(default)]
pub drop_file: bool,
#[serde(default)]
#[metadata(index=false)]
pub from_archive: bool,
}