Skip to main content

stix_rs/observables/
software_package.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub struct SoftwarePackage {
7    pub name: Option<String>,
8    pub version: Option<String>,
9    pub cpe: Option<String>,
10    pub created: Option<DateTime<Utc>>,
11    #[serde(flatten)]
12    pub custom_properties: std::collections::HashMap<String, serde_json::Value>,
13}
14
15impl SoftwarePackage {
16    pub fn builder() -> SoftwarePackageBuilder {
17        SoftwarePackageBuilder::default()
18    }
19}
20
21#[derive(Debug, Default)]
22pub struct SoftwarePackageBuilder {
23    name: Option<String>,
24    version: Option<String>,
25    cpe: Option<String>,
26    created: Option<DateTime<Utc>>,
27    custom_properties: std::collections::HashMap<String, serde_json::Value>,
28}
29
30impl SoftwarePackageBuilder {
31    pub fn name(mut self, n: impl Into<String>) -> Self {
32        self.name = Some(n.into());
33        self
34    }
35    pub fn version(mut self, v: impl Into<String>) -> Self {
36        self.version = Some(v.into());
37        self
38    }
39    pub fn cpe(mut self, c: impl Into<String>) -> Self {
40        self.cpe = Some(c.into());
41        self
42    }
43    pub fn created(mut self, d: DateTime<Utc>) -> Self {
44        self.created = Some(d);
45        self
46    }
47    pub fn property(mut self, k: impl Into<String>, val: impl Into<serde_json::Value>) -> Self {
48        self.custom_properties.insert(k.into(), val.into());
49        self
50    }
51    pub fn build(self) -> SoftwarePackage {
52        SoftwarePackage {
53            name: self.name,
54            version: self.version,
55            cpe: self.cpe,
56            created: self.created,
57            custom_properties: self.custom_properties,
58        }
59    }
60}
61
62impl From<SoftwarePackage> for crate::StixObjectEnum {
63    fn from(s: SoftwarePackage) -> Self {
64        crate::StixObjectEnum::SoftwarePackage(s)
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use serde_json::json;
71
72    #[test]
73    fn software_package_serde() {
74        let v = json!({"type": "software-package", "name": "pkg", "version": "1.2.3"});
75        let obj: crate::StixObjectEnum =
76            serde_json::from_value(v).expect("deserialize into StixObjectEnum");
77        match obj {
78            crate::StixObjectEnum::SoftwarePackage(sp) => {
79                assert_eq!(sp.name.unwrap(), "pkg");
80                assert_eq!(sp.version.unwrap(), "1.2.3");
81            }
82            _ => panic!("expected SoftwarePackage variant"),
83        }
84    }
85}