stix-rs 0.1.0

STIX 2.1 types and helpers for Rust
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::common::{CommonProperties, StixObject};
use crate::sdos::BuilderError;

/// Malware Analysis SDO
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MalwareAnalysis {
    #[serde(flatten)]
    pub common: CommonProperties,
    pub product: Option<String>,
    pub version: Option<String>,
    pub analysis_engine_version: Option<String>,
    pub result: Option<String>,
}

impl MalwareAnalysis {
    pub fn builder() -> MalwareAnalysisBuilder {
        MalwareAnalysisBuilder::default()
    }
}

#[derive(Debug, Default)]
pub struct MalwareAnalysisBuilder {
    product: Option<String>,
    version: Option<String>,
    analysis_engine_version: Option<String>,
    result: Option<String>,
    created_by_ref: Option<String>,
}

impl MalwareAnalysisBuilder {
    pub fn product(mut self, p: impl Into<String>) -> Self {
        self.product = Some(p.into());
        self
    }

    pub fn version(mut self, v: impl Into<String>) -> Self {
        self.version = Some(v.into());
        self
    }

    pub fn analysis_engine_version(mut self, v: impl Into<String>) -> Self {
        self.analysis_engine_version = Some(v.into());
        self
    }

    pub fn result(mut self, r: impl Into<String>) -> Self {
        self.result = Some(r.into());
        self
    }

    pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
        self.created_by_ref = Some(r.into());
        self
    }

    pub fn build(self) -> Result<MalwareAnalysis, BuilderError> {
        let common = CommonProperties::new("malware-analysis", self.created_by_ref);
        Ok(MalwareAnalysis {
            common,
            product: self.product,
            version: self.version,
            analysis_engine_version: self.analysis_engine_version,
            result: self.result,
        })
    }
}

impl StixObject for MalwareAnalysis {
    fn id(&self) -> &str {
        &self.common.id
    }

    fn type_(&self) -> &str {
        &self.common.r#type
    }

    fn created(&self) -> DateTime<Utc> {
        self.common.created
    }
}

impl From<MalwareAnalysis> for crate::StixObjectEnum {
    fn from(m: MalwareAnalysis) -> Self {
        crate::StixObjectEnum::MalwareAnalysis(m)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::Value;

    #[test]
    fn malware_analysis_builder() {
        let ma = MalwareAnalysis::builder()
            .product("AV")
            .version("1.0")
            .result("clean")
            .build()
            .unwrap();

        assert_eq!(ma.product.as_deref(), Some("AV"));
        assert_eq!(ma.common.r#type, "malware-analysis");
    }

    #[test]
    fn malware_analysis_serialize() {
        let ma = MalwareAnalysis::builder()
            .product("AV")
            .version("1.0")
            .result("clean")
            .build()
            .unwrap();

        let s = serde_json::to_string(&ma).unwrap();
        let v: Value = serde_json::from_str(&s).unwrap();
        assert_eq!(
            v.get("type").and_then(Value::as_str).unwrap(),
            "malware-analysis"
        );
    }
}