maec/objects/
malware_instance.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::common::MaecObject;
7use crate::error::{MaecError, Result};
8use crate::objects::types::{FieldData, Name};
9use crate::Capability;
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "snake_case")]
17pub struct MalwareInstance {
18 #[serde(flatten)]
20 pub common: crate::common::CommonProperties,
21
22 pub instance_object_refs: Vec<String>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub name: Option<Name>,
28
29 #[serde(default, skip_serializing_if = "Vec::is_empty")]
31 pub aliases: Vec<Name>,
32
33 #[serde(default, skip_serializing_if = "Vec::is_empty")]
35 pub labels: Vec<String>,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub description: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub field_data: Option<FieldData>,
44
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub os_execution_envs: Vec<String>,
48
49 #[serde(default, skip_serializing_if = "Vec::is_empty")]
51 pub architecture_execution_envs: Vec<String>,
52
53 #[serde(default, skip_serializing_if = "Vec::is_empty")]
55 pub capabilities: Vec<Capability>,
56
57 #[serde(default, skip_serializing_if = "Vec::is_empty")]
59 pub os_features: Vec<String>,
60}
61
62impl MalwareInstance {
63 pub fn builder() -> MalwareInstanceBuilder {
65 MalwareInstanceBuilder::default()
66 }
67
68 pub fn new(instance_object_refs: Vec<String>) -> Self {
70 Self {
71 common: crate::common::CommonProperties::new("malware-instance", None),
72 instance_object_refs,
73 name: None,
74 aliases: vec![],
75 labels: vec![],
76 description: None,
77 field_data: None,
78 os_execution_envs: vec![],
79 architecture_execution_envs: vec![],
80 capabilities: vec![],
81 os_features: vec![],
82 }
83 }
84
85 pub fn validate(&self) -> Result<()> {
87 if self.common.r#type != "malware-instance" {
88 return Err(MaecError::ValidationError(format!(
89 "type must be 'malware-instance', got '{}'",
90 self.common.r#type
91 )));
92 }
93
94 if !crate::common::is_valid_maec_id(&self.common.id) {
95 return Err(MaecError::InvalidId(self.common.id.clone()));
96 }
97
98 if self.instance_object_refs.is_empty() {
99 return Err(MaecError::MissingField("instance_object_refs"));
100 }
101
102 Ok(())
103 }
104}
105
106impl MaecObject for MalwareInstance {
107 fn id(&self) -> &str {
108 &self.common.id
109 }
110
111 fn type_(&self) -> &str {
112 &self.common.r#type
113 }
114
115 fn created(&self) -> DateTime<Utc> {
116 self.common.created
117 }
118}
119
120#[derive(Debug, Default)]
122pub struct MalwareInstanceBuilder {
123 id: Option<String>,
124 instance_object_refs: Vec<String>,
125 name: Option<Name>,
126 aliases: Vec<Name>,
127 labels: Vec<String>,
128 description: Option<String>,
129 field_data: Option<FieldData>,
130 os_execution_envs: Vec<String>,
131 architecture_execution_envs: Vec<String>,
132 capabilities: Vec<Capability>,
133 os_features: Vec<String>,
134}
135
136impl MalwareInstanceBuilder {
137 pub fn id(mut self, id: impl Into<String>) -> Self {
138 self.id = Some(id.into());
139 self
140 }
141
142 pub fn add_instance_object_ref(mut self, ref_id: impl Into<String>) -> Self {
143 self.instance_object_refs.push(ref_id.into());
144 self
145 }
146
147 pub fn instance_object_refs(mut self, refs: Vec<String>) -> Self {
148 self.instance_object_refs = refs;
149 self
150 }
151
152 pub fn name(mut self, name: impl Into<Name>) -> Self {
153 self.name = Some(name.into());
154 self
155 }
156
157 pub fn description(mut self, desc: impl Into<String>) -> Self {
158 self.description = Some(desc.into());
159 self
160 }
161
162 pub fn add_label(mut self, label: impl Into<String>) -> Self {
163 self.labels.push(label.into());
164 self
165 }
166
167 pub fn field_data(mut self, field_data: FieldData) -> Self {
168 self.field_data = Some(field_data);
169 self
170 }
171
172 pub fn add_capability(mut self, capability: Capability) -> Self {
173 self.capabilities.push(capability);
174 self
175 }
176
177 pub fn build(self) -> Result<MalwareInstance> {
178 if self.instance_object_refs.is_empty() {
179 return Err(MaecError::MissingField("instance_object_refs"));
180 }
181
182 let mut common = crate::common::CommonProperties::new("malware-instance", None);
183 if let Some(id) = self.id {
184 common.id = id;
185 }
186
187 let instance = MalwareInstance {
188 common,
189 instance_object_refs: self.instance_object_refs,
190 name: self.name,
191 aliases: self.aliases,
192 labels: self.labels,
193 description: self.description,
194 field_data: self.field_data,
195 os_execution_envs: self.os_execution_envs,
196 architecture_execution_envs: self.architecture_execution_envs,
197 capabilities: self.capabilities,
198 os_features: self.os_features,
199 };
200
201 instance.validate()?;
202 Ok(instance)
203 }
204}