Skip to main content

stix_rs/sdos/
intrusion_set.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5use crate::sdos::BuilderError;
6
7/// Intrusion Set SDO
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub struct IntrusionSet {
11    #[serde(flatten)]
12    pub common: CommonProperties,
13    pub name: String,
14    pub description: Option<String>,
15}
16
17impl IntrusionSet {
18    pub fn builder() -> IntrusionSetBuilder {
19        IntrusionSetBuilder::default()
20    }
21}
22
23#[derive(Debug, Default)]
24pub struct IntrusionSetBuilder {
25    name: Option<String>,
26    description: Option<String>,
27    created_by_ref: Option<String>,
28}
29
30impl IntrusionSetBuilder {
31    pub fn name(mut self, name: impl Into<String>) -> Self {
32        self.name = Some(name.into());
33        self
34    }
35
36    pub fn description(mut self, d: impl Into<String>) -> Self {
37        self.description = Some(d.into());
38        self
39    }
40
41    pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
42        self.created_by_ref = Some(r.into());
43        self
44    }
45
46    pub fn build(self) -> Result<IntrusionSet, BuilderError> {
47        let name = self.name.ok_or(BuilderError::MissingField("name"))?;
48        let common = CommonProperties::new("intrusion-set", self.created_by_ref);
49        Ok(IntrusionSet {
50            common,
51            name,
52            description: self.description,
53        })
54    }
55}
56
57impl StixObject for IntrusionSet {
58    fn id(&self) -> &str {
59        &self.common.id
60    }
61
62    fn type_(&self) -> &str {
63        &self.common.r#type
64    }
65
66    fn created(&self) -> DateTime<Utc> {
67        self.common.created
68    }
69}
70
71impl From<IntrusionSet> for crate::StixObjectEnum {
72    fn from(i: IntrusionSet) -> Self {
73        crate::StixObjectEnum::IntrusionSet(i)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn intrusion_set_builder() {
83        let iset = IntrusionSet::builder()
84            .name("Lazarus Group")
85            .description("North Korean APT group")
86            .build()
87            .unwrap();
88
89        assert_eq!(iset.name, "Lazarus Group");
90        assert_eq!(iset.common.r#type, "intrusion-set");
91    }
92
93    #[test]
94    fn intrusion_set_serialize() {
95        let iset = IntrusionSet::builder().name("Fancy Bear").build().unwrap();
96
97        let json = serde_json::to_string(&iset).unwrap();
98        assert!(json.contains("\"type\":\"intrusion-set\""));
99        assert!(json.contains("\"name\":\"Fancy Bear\""));
100    }
101}