Skip to main content

stix_rs/sdos/
note.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5use crate::sdos::BuilderError;
6
7/// Note SDO
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub struct Note {
11    #[serde(flatten)]
12    pub common: CommonProperties,
13    #[serde(rename = "abstract")]
14    pub abstract_: Option<String>,
15    pub content: Option<String>,
16}
17
18impl Note {
19    pub fn builder() -> NoteBuilder {
20        NoteBuilder::default()
21    }
22}
23
24#[derive(Debug, Default)]
25pub struct NoteBuilder {
26    abstract_: Option<String>,
27    content: Option<String>,
28    created_by_ref: Option<String>,
29}
30
31impl NoteBuilder {
32    pub fn abstract_(mut self, a: impl Into<String>) -> Self {
33        self.abstract_ = Some(a.into());
34        self
35    }
36
37    pub fn content(mut self, c: impl Into<String>) -> Self {
38        self.content = Some(c.into());
39        self
40    }
41
42    pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
43        self.created_by_ref = Some(r.into());
44        self
45    }
46
47    pub fn build(self) -> Result<Note, BuilderError> {
48        let common = CommonProperties::new("note", self.created_by_ref);
49        Ok(Note {
50            common,
51            abstract_: self.abstract_,
52            content: self.content,
53        })
54    }
55}
56
57impl StixObject for Note {
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<Note> for crate::StixObjectEnum {
72    fn from(n: Note) -> Self {
73        crate::StixObjectEnum::Note(n)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn note_builder() {
83        let note = Note::builder()
84            .abstract_("Summary of findings")
85            .content("Detailed analysis of the threat actor's TTPs")
86            .build()
87            .unwrap();
88
89        assert_eq!(note.abstract_.as_deref(), Some("Summary of findings"));
90        assert_eq!(note.common.r#type, "note");
91    }
92
93    #[test]
94    fn note_serialize() {
95        let note = Note::builder()
96            .content("Important observation")
97            .build()
98            .unwrap();
99
100        let json = serde_json::to_string(&note).unwrap();
101        assert!(json.contains("\"type\":\"note\""));
102        assert!(json.contains("\"content\":\"Important observation\""));
103    }
104}