1mod ast;
2mod lexer;
3
4use crate::detection::ast::Ast;
5use crate::error::ParserError;
6use crate::event::Event;
7use crate::selection::Selection;
8use crate::wildcard::match_tokenized;
9use serde::Deserialize;
10use serde_yml::Value;
11use std::collections::HashMap;
12
13#[derive(Deserialize, Debug)]
14struct DetectionProxy {
15 #[serde(flatten)]
16 selections: HashMap<String, Value>,
17 condition: String,
18}
19
20#[derive(Debug, Deserialize)]
21#[serde(try_from = "DetectionProxy")]
22pub struct Detection {
23 #[serde(flatten)]
24 selections: HashMap<String, Selection>,
25 condition: String,
26 #[serde(skip)]
27 ast: Ast,
28}
29
30impl TryFrom<DetectionProxy> for Detection {
31 type Error = ParserError;
32
33 fn try_from(other: DetectionProxy) -> Result<Self, Self::Error> {
34 let mut selections = HashMap::with_capacity(other.selections.len());
35 for (name, selection) in other.selections {
36 match Selection::try_from(selection) {
37 Ok(selection) => {
38 selections.insert(name, selection);
39 }
40 Err(e) => {
41 return match e {
42 ParserError::SelectionParsingError(_, se) => {
43 Err(ParserError::SelectionParsingError(name, se))
44 }
45 _ => Err(e),
46 }
47 }
48 }
49 }
50 let result = Self::new(selections, other.condition)?;
51 Ok(result)
52 }
53}
54
55impl Detection {
56 pub fn get_selections(&self) -> &HashMap<String, Selection> {
57 &self.selections
58 }
59
60 pub fn get_condition(&self) -> &str {
61 &self.condition
62 }
63
64 pub(crate) fn new<S: AsRef<str>>(
65 selections: HashMap<String, Selection>,
66 condition: S,
67 ) -> Result<Self, ParserError> {
68 let mut result = Self {
69 selections,
70 condition: condition.as_ref().into(),
71 ast: Ast::default(),
72 };
73 result.parse_ast()?;
74 Ok(result)
75 }
76
77 pub(crate) fn parse_ast(&mut self) -> Result<(), ParserError> {
78 let ast = Ast::new(self.condition.as_str())?;
79 let identifiers = ast.selections();
80
81 let missing: Vec<String> = identifiers
82 .into_iter()
83 .filter(|i| !self.selections.contains_key(*i))
84 .map(|i| i.to_string())
85 .collect();
86
87 if !missing.is_empty() {
88 return Err(ParserError::UndefinedIdentifiers(missing));
89 }
90
91 self.ast = ast;
92 Ok(())
93 }
94
95 pub(crate) fn evaluate(&self, event: &Event) -> bool {
96 self.eval(event, &self.ast, &mut HashMap::new())
97 }
98
99 fn evaluate_selection(
100 &self,
101 name: &str,
102 lookup: &mut HashMap<String, bool>,
103 event: &Event,
104 ) -> bool {
105 if let Some(e) = lookup.get(name) {
106 *e
107 } else if let Some(selection) = self.selections.get(name) {
108 let eval = selection.evaluate(event);
109 lookup.insert(name.to_string(), eval);
110 eval
111 } else {
112 false
115 }
116 }
117
118 fn eval(&self, event: &Event, ast: &Ast, lookup: &mut HashMap<String, bool>) -> bool {
119 match ast {
120 Ast::Selection(s) => self.evaluate_selection(s, lookup, event),
121 Ast::OneOf(s) => self
122 .selections
123 .keys()
124 .filter(|name| match_tokenized(s, name, false))
125 .any(|name| self.evaluate_selection(name, lookup, event)),
126 Ast::OneOfThem => self
127 .selections
128 .keys()
129 .any(|name| self.evaluate_selection(name, lookup, event)),
130 Ast::AllOf(s) => self
131 .selections
132 .keys()
133 .filter(|name| match_tokenized(s, name, false))
134 .all(|name| self.evaluate_selection(name, lookup, event)),
135 Ast::AllOfThem => self
136 .selections
137 .keys()
138 .all(|name| self.evaluate_selection(name, lookup, event)),
139 Ast::Not(ref operand) => !self.eval(event, operand, lookup),
140 Ast::Or(ref left, ref right) => {
141 self.eval(event, left, lookup) || self.eval(event, right, lookup)
142 }
143 Ast::And(ref left, ref right) => {
144 self.eval(event, left, lookup) && self.eval(event, right, lookup)
145 }
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn test_missing_identifier() {
156 let err = Detection::new(HashMap::new(), "selection1 and selection2").unwrap_err();
157 assert!(matches!(err, ParserError::UndefinedIdentifiers(_)));
158 }
159
160 #[test]
161 fn test_evaluate() {
162 let detection_yaml = r#"
163 selection_1:
164 EventID: 6416
165 RandomID|contains:
166 - ab
167 - cd
168 - ed
169 selection_2:
170 EventID: 5555
171 condition: selection_1 or selection_2
172"#;
173
174 let mut event = Event::from([("EventID", 6416)]);
175 event.insert("RandomID", "ab");
176
177 let detection: Detection = serde_yml::from_str(detection_yaml).unwrap();
178 assert_eq!(detection.selections.len(), 2);
179 let result = detection.evaluate(&event);
180 assert!(result);
181
182 let detection =
183 Detection::new(detection.selections, "selection_1 and selection_2").unwrap();
184 let result = detection.evaluate(&event);
185 assert!(!result);
186 }
187
188 #[test]
189 fn test_evaluate_one_all_of_them() {
190 let detection_yaml = r#"
191 selection_1:
192 EventID: 6416
193 RandomID|contains:
194 - ab
195 - cd
196 - ed
197 selection_2:
198 EventID: 5555
199 condition: 1 of them
200"#;
201
202 let mut event = Event::from([("EventID", 6416)]);
203 event.insert("RandomID", "ab");
204
205 let detection: Detection = serde_yml::from_str(detection_yaml).unwrap();
206 assert_eq!(detection.selections.len(), 2);
207 let result = detection.evaluate(&event);
208 assert!(result);
209
210 let detection = Detection::new(detection.selections, "all of them").unwrap();
211 let result = detection.evaluate(&event);
212 assert!(!result);
213 }
214
215 #[test]
216 fn test_evaluate_one_of() {
217 let detection_yaml = r#"
218 selection_1:
219 EventID: 6416
220 RandomID|contains:
221 - ab
222 - cd
223 - ed
224 selection_2:
225 EventID: 5555
226 condition: 1 of selection*
227"#;
228
229 let mut event = Event::from([("EventID", 6416)]);
230 event.insert("RandomID", "ab");
231
232 let detection: Detection = serde_yml::from_str(detection_yaml).unwrap();
233 assert_eq!(detection.selections.len(), 2);
234 let result = detection.evaluate(&event);
235 assert!(result);
236
237 let detection = Detection::new(detection.selections, "1 of nothing*").unwrap();
238 let result = detection.evaluate(&event);
239 assert!(!result);
240 }
241
242 #[test]
243 fn test_evaluate_all_of() {
244 let detection_yaml = r#"
245 selection_1x:
246 EventID: 6416
247 RandomID|contains:
248 - ab
249 - cd
250 - ed
251 selection_2x:
252 EventID: 5555
253 condition: all of sel*tion*x
254"#;
255
256 let mut event = Event::from([("EventID", 6416)]);
257 event.insert("RandomID", "ab");
258
259 let detection: Detection = serde_yml::from_str(detection_yaml).unwrap();
260 assert_eq!(detection.selections.len(), 2);
261 let result = detection.evaluate(&event);
262 assert!(!result);
263
264 let detection = Detection::new(detection.selections, "all of selection_1*").unwrap();
265 let result = detection.evaluate(&event);
266 assert!(result);
267
268 let detection = Detection::new(detection.selections, "all of nothing*").unwrap();
269 let result = detection.evaluate(&event);
270 assert!(result);
271 }
272}