stix_rs/sdos/
infrastructure.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5use crate::sdos::BuilderError;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub struct Infrastructure {
11 #[serde(flatten)]
12 pub common: CommonProperties,
13 pub name: String,
14 pub description: Option<String>,
15 pub infrastructure_types: Option<Vec<String>>,
16}
17
18impl Infrastructure {
19 pub fn builder() -> InfrastructureBuilder {
20 InfrastructureBuilder::default()
21 }
22}
23
24#[derive(Debug, Default)]
25pub struct InfrastructureBuilder {
26 name: Option<String>,
27 description: Option<String>,
28 infrastructure_types: Option<Vec<String>>,
29 created_by_ref: Option<String>,
30}
31
32impl InfrastructureBuilder {
33 pub fn name(mut self, name: impl Into<String>) -> Self {
34 self.name = Some(name.into());
35 self
36 }
37
38 pub fn description(mut self, d: impl Into<String>) -> Self {
39 self.description = Some(d.into());
40 self
41 }
42
43 pub fn infrastructure_types(mut self, t: Vec<String>) -> Self {
44 self.infrastructure_types = Some(t);
45 self
46 }
47
48 pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
49 self.created_by_ref = Some(r.into());
50 self
51 }
52
53 pub fn build(self) -> Result<Infrastructure, BuilderError> {
54 let name = self.name.ok_or(BuilderError::MissingField("name"))?;
55 let common = CommonProperties::new("infrastructure", self.created_by_ref);
56 Ok(Infrastructure {
57 common,
58 name,
59 description: self.description,
60 infrastructure_types: self.infrastructure_types,
61 })
62 }
63}
64
65impl StixObject for Infrastructure {
66 fn id(&self) -> &str {
67 &self.common.id
68 }
69
70 fn type_(&self) -> &str {
71 &self.common.r#type
72 }
73
74 fn created(&self) -> DateTime<Utc> {
75 self.common.created
76 }
77}
78
79impl From<Infrastructure> for crate::StixObjectEnum {
80 fn from(i: Infrastructure) -> Self {
81 crate::StixObjectEnum::Infrastructure(i)
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn infrastructure_builder() {
91 let infra = Infrastructure::builder()
92 .name("C2 Server")
93 .description("Command and control infrastructure")
94 .infrastructure_types(vec!["command-and-control".into()])
95 .build()
96 .unwrap();
97
98 assert_eq!(infra.name, "C2 Server");
99 assert_eq!(infra.common.r#type, "infrastructure");
100 }
101
102 #[test]
103 fn infrastructure_serialize() {
104 let infra = Infrastructure::builder()
105 .name("Malicious Domain")
106 .build()
107 .unwrap();
108
109 let json = serde_json::to_string(&infra).unwrap();
110 assert!(json.contains("\"type\":\"infrastructure\""));
111 assert!(json.contains("\"name\":\"Malicious Domain\""));
112 }
113}