Skip to main content

maec/objects/
capability.rs

1//! MAEC Capability type implementation
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6use crate::common::ExternalReference;
7use crate::error::Result;
8
9/// MAEC Capability
10///
11/// Captures details of a Capability that may be implemented in the malware instance.
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub struct Capability {
15    /// Name of the capability
16    pub name: String,
17
18    /// Refined sub-capabilities
19    #[serde(default, skip_serializing_if = "Vec::is_empty")]
20    pub refined_capabilities: Vec<Capability>,
21
22    /// Textual description
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub description: Option<String>,
25
26    /// Capability attributes as key/value pairs
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub attributes: Option<HashMap<String, serde_json::Value>>,
29
30    /// References to behaviors implementing this capability
31    #[serde(default, skip_serializing_if = "Vec::is_empty")]
32    pub behavior_refs: Vec<String>,
33
34    /// External references (ATT&CK tactics, etc.)
35    #[serde(default, skip_serializing_if = "Vec::is_empty")]
36    pub references: Vec<ExternalReference>,
37}
38
39impl Capability {
40    /// Creates a new Capability with just a name
41    pub fn new(name: impl Into<String>) -> Self {
42        Self {
43            name: name.into(),
44            refined_capabilities: vec![],
45            description: None,
46            attributes: None,
47            behavior_refs: vec![],
48            references: vec![],
49        }
50    }
51
52    /// Creates a new Capability builder
53    pub fn builder() -> CapabilityBuilder {
54        CapabilityBuilder::default()
55    }
56}
57
58/// Builder for Capability objects
59#[derive(Debug, Default)]
60pub struct CapabilityBuilder {
61    name: Option<String>,
62    refined_capabilities: Vec<Capability>,
63    description: Option<String>,
64    attributes: Option<HashMap<String, serde_json::Value>>,
65    behavior_refs: Vec<String>,
66    references: Vec<ExternalReference>,
67}
68
69impl CapabilityBuilder {
70    pub fn name(mut self, name: impl Into<String>) -> Self {
71        self.name = Some(name.into());
72        self
73    }
74
75    pub fn description(mut self, desc: impl Into<String>) -> Self {
76        self.description = Some(desc.into());
77        self
78    }
79
80    pub fn add_refined_capability(mut self, capability: Capability) -> Self {
81        self.refined_capabilities.push(capability);
82        self
83    }
84
85    pub fn add_behavior_ref(mut self, ref_id: impl Into<String>) -> Self {
86        self.behavior_refs.push(ref_id.into());
87        self
88    }
89
90    pub fn add_reference(mut self, reference: ExternalReference) -> Self {
91        self.references.push(reference);
92        self
93    }
94
95    pub fn build(self) -> Result<Capability> {
96        let name = self
97            .name
98            .ok_or(crate::error::MaecError::MissingField("name"))?;
99
100        Ok(Capability {
101            name,
102            refined_capabilities: self.refined_capabilities,
103            description: self.description,
104            attributes: self.attributes,
105            behavior_refs: self.behavior_refs,
106            references: self.references,
107        })
108    }
109}