use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use struct_metadata::Described;
use crate::{JsonMap, Sha256, ExpandingClassification, ElasticMeta, Sid, ClassificationString};
#[derive(Serialize, Deserialize, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=true)]
pub struct Submission {
pub archived: bool,
#[serde(flatten)]
pub classification: ExpandingClassification,
pub error_count: i32,
#[metadata(store=false)]
pub errors: Vec<String>,
#[metadata(store=false)]
pub expiry_ts: Option<DateTime<Utc>>,
pub file_count: i32,
pub file: File,
pub max_score: i32,
#[metadata(store=false)]
pub metadata: HashMap<String, String>,
pub params: SubmissionParams,
#[metadata(store=false)]
pub results: Vec<String>,
#[metadata(copyto="__text__")]
pub sid: Sid,
pub state: SubmissionState,
pub to_be_deleted: bool,
pub times: Times,
pub verdict: Verdict,
#[metadata(index=false)]
pub from_archive: bool,
#[metadata(index=false, store=false)]
pub scan_key: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct SubmissionParams {
pub classification: ClassificationString,
pub deep_scan: bool,
#[serde(skip_serializing_if = "Option::is_none")]
#[metadata(store=true, copyto="__text__")]
pub description: Option<String>,
pub generate_alert: bool,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<String>,
pub ignore_cache: bool,
pub ignore_dynamic_recursion_prevention: bool,
pub ignore_filtering: bool,
pub ignore_size: bool,
pub never_drop: bool,
pub malicious: bool,
pub max_extracted: u32,
pub max_supplementary: u32,
pub priority: u16,
pub profile: bool,
pub quota_item: bool,
pub services: ServiceSelection,
#[metadata(index=false, store=false)]
pub service_spec: HashMap<String, JsonMap>,
#[metadata(store=true, copyto="__text__")]
pub submitter: String,
pub ttl: u32,
#[serde(rename="type")]
pub submission_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[metadata(index=false)]
pub initial_data: Option<String>,
pub auto_archive: bool,
pub delete_after_archive: bool
}
impl Default for SubmissionParams {
fn default() -> Self {
Self {
classification: ClassificationString::new("".to_owned()).unwrap(),
deep_scan: false,
description: None,
generate_alert: false,
groups: vec![],
ignore_cache: false,
ignore_dynamic_recursion_prevention: false,
ignore_filtering: false,
ignore_size: false,
never_drop: false,
malicious: false,
max_extracted: 100,
max_supplementary: 100,
priority: 100,
profile: false,
quota_item: false,
services: Default::default(),
service_spec: Default::default(),
submitter: "USER".to_owned(),
ttl: 30,
submission_type: "USER".to_owned(),
initial_data: None,
auto_archive: false,
delete_after_archive: false,
}
}
}
#[derive(Serialize, Deserialize, Default, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=false, store=false)]
pub struct ServiceSelection {
#[serde(skip_serializing_if = "Option::is_none")]
pub selected: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub excluded: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rescan: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resubmit: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=true)]
pub struct Times {
#[metadata(store=false)]
pub completed: Option<DateTime<Utc>>,
pub submitted: DateTime<Utc>,
}
#[derive(Serialize, Deserialize, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct Verdict {
#[serde(default)]
pub malicious: Vec<String>,
#[serde(default)]
pub non_malicious: Vec<String>,
}
#[derive(Serialize, Debug, PartialEq, Eq, strum::Display, Described, Clone, Copy)]
#[metadata_type(ElasticMeta)]
pub enum SubmissionState {
Failed,
Submitted,
Completed,
}
impl<'de> Deserialize<'de> for SubmissionState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>
{
let string = String::deserialize(deserializer)?;
match string.to_lowercase().as_str() {
"failed" => Ok(Self::Failed),
"submitted" => Ok(Self::Submitted),
"completed" => Ok(Self::Completed),
_ => Err(serde::de::Error::custom("unparsable submission state")),
}
}
}
#[derive(Serialize, Deserialize, Debug, Described, Clone)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=false)]
pub struct File {
#[metadata(copyto="__text__")]
pub name: String,
pub size: Option<u64>,
#[metadata(copyto="__text__")]
pub sha256: Sha256,
}