Skip to main content

maec/objects/
malware_action.rs

1//! MAEC Malware Action object
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::common::{CommonProperties, MaecObject};
7use crate::error::{MaecError, Result};
8use crate::vocab_large::MalwareAction as MalwareActionVocab;
9
10/// MAEC Malware Action
11///
12/// Represents a low-level action taken by malware (e.g., file operations, network connections).
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
14#[serde(rename_all = "snake_case")]
15pub struct MalwareAction {
16    /// Common MAEC properties
17    #[serde(flatten)]
18    pub common: CommonProperties,
19
20    /// Name of the action
21    pub name: MalwareActionVocab,
22
23    /// Textual description
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub description: Option<String>,
26}
27
28impl MalwareAction {
29    /// Creates a new MalwareAction builder
30    pub fn builder() -> MalwareActionBuilder {
31        MalwareActionBuilder::default()
32    }
33
34    /// Creates a minimal MalwareAction with just a name
35    pub fn new(name: MalwareActionVocab) -> Self {
36        Self {
37            common: CommonProperties::new("malware-action", None),
38            name,
39            description: None,
40        }
41    }
42
43    /// Validates the MalwareAction structure
44    pub fn validate(&self) -> Result<()> {
45        if self.common.r#type != "malware-action" {
46            return Err(MaecError::ValidationError(format!(
47                "type must be 'malware-action', got '{}'",
48                self.common.r#type
49            )));
50        }
51
52        if !crate::common::is_valid_maec_id(&self.common.id) {
53            return Err(MaecError::InvalidId(self.common.id.clone()));
54        }
55
56        Ok(())
57    }
58}
59
60impl MaecObject for MalwareAction {
61    fn id(&self) -> &str {
62        &self.common.id
63    }
64
65    fn type_(&self) -> &str {
66        &self.common.r#type
67    }
68
69    fn created(&self) -> DateTime<Utc> {
70        self.common.created
71    }
72}
73
74/// Builder for MalwareAction objects
75#[derive(Debug, Default)]
76pub struct MalwareActionBuilder {
77    id: Option<String>,
78    name: Option<MalwareActionVocab>,
79    description: Option<String>,
80}
81
82impl MalwareActionBuilder {
83    pub fn id(mut self, id: impl Into<String>) -> Self {
84        self.id = Some(id.into());
85        self
86    }
87
88    pub fn name(mut self, name: MalwareActionVocab) -> Self {
89        self.name = Some(name);
90        self
91    }
92
93    pub fn description(mut self, desc: impl Into<String>) -> Self {
94        self.description = Some(desc.into());
95        self
96    }
97
98    pub fn build(self) -> Result<MalwareAction> {
99        let name = self.name.ok_or(MaecError::MissingField("name"))?;
100
101        let mut common = CommonProperties::new("malware-action", None);
102        if let Some(id) = self.id {
103            common.id = id;
104        }
105
106        let action = MalwareAction {
107            common,
108            name,
109            description: self.description,
110        };
111
112        action.validate()?;
113        Ok(action)
114    }
115}