1use crate::error::ParserError;
2use crate::error::SelectionError::{
3 InvalidKeywordSelection, InvalidSelectionType, MixedKeywordAndFieldlist,
4 SelectionContainsNoFields,
5};
6use crate::event::Event;
7use crate::field::Field;
8use serde::Deserialize;
9use serde_yml::Value;
10use serde_yml::Value::{Mapping, Sequence};
11
12#[derive(Debug)]
15pub struct FieldGroup {
16 pub fields: Vec<Field>,
17}
18
19impl FieldGroup {
20 fn evaluate(&self, event: &Event) -> bool {
21 self.fields.iter().all(|field| field.evaluate(event))
22 }
23}
24
25impl TryFrom<serde_yml::Mapping> for FieldGroup {
26 type Error = ParserError;
27 fn try_from(mapping: serde_yml::Mapping) -> Result<Self, Self::Error> {
28 let mut fields = vec![];
29 for (name, values) in mapping.into_iter() {
30 match name {
31 Value::String(name) => fields.push(Field::from_yaml(name, values)?),
32 _ => return Err(Self::Error::InvalidFieldName(format!("{:?}", name))),
33 }
34 }
35 Ok(Self { fields })
36 }
37}
38
39#[derive(Deserialize)]
40struct SelectionProxy {
41 #[serde(flatten)]
42 value: Value,
43}
44
45#[derive(Debug, Deserialize)]
46#[serde(try_from = "SelectionProxy")]
47pub enum Selection {
48 Keyword(Vec<String>),
49 Field(Vec<FieldGroup>),
50}
51
52impl TryFrom<SelectionProxy> for Selection {
53 type Error = ParserError;
54
55 fn try_from(other: SelectionProxy) -> Result<Self, Self::Error> {
56 Self::try_from(other.value)
57 }
58}
59
60impl TryFrom<Value> for Selection {
61 type Error = ParserError;
62 fn try_from(other: Value) -> Result<Self, Self::Error> {
63 match other {
64 Sequence(seq) => {
65 if seq.is_empty() {
66 return Err(Self::Error::SelectionParsingError(
67 String::new(),
68 SelectionContainsNoFields(),
69 ));
70 }
71 let is_keyword_selection = !seq[0].is_mapping();
72 if is_keyword_selection {
73 let mut keywords = vec![];
74 for value in seq.iter() {
75 match value {
76 Value::String(s) => keywords.push(s.to_string()),
77 Value::Number(n) => keywords.push(n.to_string()),
78 Value::Bool(b) => keywords.push(b.to_string()),
79 _ => {
80 return Err(Self::Error::SelectionParsingError(
81 String::new(),
82 InvalidKeywordSelection(format!("{:?}", value)),
83 ))
84 }
85 }
86 }
87 return Ok(Self::Keyword(keywords));
88 }
89 let mut field_groups = vec![];
91 for value in seq {
92 match value {
93 Mapping(map) => {
94 field_groups.push(FieldGroup::try_from(map)?);
95 }
96 _ => {
97 return Err(Self::Error::SelectionParsingError(
98 String::new(),
99 MixedKeywordAndFieldlist(),
100 ))
101 }
102 }
103 }
104 Ok(Self::Field(field_groups))
105 }
106 Mapping(mapping) => {
107 let field_group = FieldGroup::try_from(mapping)?;
108 Ok(Self::Field(vec![field_group]))
109 }
110 _ => Err(Self::Error::SelectionParsingError(
111 String::new(),
112 InvalidSelectionType(),
113 )),
114 }
115 }
116}
117
118impl Selection {
119 pub(crate) fn evaluate(&self, event: &Event) -> bool {
120 match &self {
121 Self::Keyword(keywords) => event
122 .values()
123 .any(|v| keywords.iter().any(|kw| v.contains_keyword(kw))),
124 Self::Field(field_groups) => field_groups.iter().any(|g| g.evaluate(event)),
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::basevalue::BaseValue;
133 use crate::event::Event;
134 use crate::field::{FieldValue, MatchModifier};
135 use serde_yml::Value;
136
137 #[test]
138 fn test_keyword_selection() {
139 let selection = Selection::Keyword(vec![
140 "test".to_string(),
141 "l?nux".to_string(),
142 "arch *".to_string(),
143 ]);
144
145 let event = Event::from([("key", "test")]);
146 assert!(selection.evaluate(&event));
147
148 let event = Event::from([("nomatch", "zsh".to_string())]);
149 assert!(!selection.evaluate(&event));
150
151 let event = Event::from([("some", "arch linux".to_string())]);
152 assert!(selection.evaluate(&event));
153
154 let event = Event::from([("some", "linux".to_string())]);
155 assert!(selection.evaluate(&event));
156
157 let event = Event::from([("some", "LINUX".to_string())]);
158 assert!(selection.evaluate(&event));
159
160 let event = Event::from([("some", "linus".to_string())]);
161 assert!(!selection.evaluate(&event));
162 }
163
164 #[test]
165 fn test_fields_selection() {
166 let selection = Selection::Field(vec![FieldGroup {
167 fields: vec![
168 Field::new(
169 "name1|contains",
170 vec![FieldValue::from("hello"), FieldValue::from("world")],
171 )
172 .unwrap(),
173 Field::new("name2|cidr", vec![FieldValue::from("10.0.0.0/16")]).unwrap(),
174 ],
175 }]);
176
177 let event = Event::from([("name1", "the world is big"), ("name2", "10.0.43.44")]);
178 assert!(selection.evaluate(&event));
179
180 let event = Event::from([("nomatch", "the world is big"), ("name2", "10.42.43.44")]);
181 assert!(!selection.evaluate(&event));
182 }
183
184 #[test]
185 fn test_new_keyword_selection() {
186 let keywords = vec!["test".to_string(), "linux".to_string(), "arch".to_string()];
187 let value = Value::from(keywords.clone());
188
189 let selection = Selection::try_from(value).unwrap();
190 assert!(matches!(selection, Selection::Keyword(kw) if kw.len() == keywords.len()));
191 }
192
193 #[test]
194 fn test_mixed_keyword_selection() {
195 let yaml = r#"
196 - 0
197 - 6
198 - hello
199 "#;
200
201 let value: Value = serde_yml::from_str(yaml).unwrap();
202 let selection = Selection::try_from(value).unwrap();
203 assert!(
204 matches!(selection, Selection::Keyword(kw) if kw.len() == 3 && kw[0] == "0" && kw[1] == "6" && kw[2] == "hello")
205 );
206 }
207
208 #[test]
209 fn test_invalid_keyword_selection() {
210 let yaml = r#"
211 - 0
212 - 6
213 - hello: world
214 "#;
215
216 let value: Value = serde_yml::from_str(yaml).unwrap();
217 let err = Selection::try_from(value).unwrap_err();
218 assert!(matches!(
219 err,
220 ParserError::SelectionParsingError(_, InvalidKeywordSelection(_)),
221 ));
222 }
223
224 #[test]
225 fn test_new_fields_selection() {
226 let yaml = r#"
227 selection:
228 EventID: 6416
229 Float: 42.21
230 ClassName: 'DiskDrive'
231 RandomID|contains:
232 - ab
233 - cd
234 - ed
235"#;
236 let data: serde_yml::Mapping = serde_yml::from_str(yaml).unwrap();
237 assert_eq!(data.len(), 1);
238
239 let value = data.values().next().unwrap().clone();
240 let selection = Selection::try_from(value).unwrap();
241
242 match selection {
243 Selection::Field(field_group) => {
244 assert_eq!(field_group.len(), 1);
245 let fields = &field_group[0].fields;
246 assert_eq!(fields[0].name, "EventID");
247 assert_eq!(fields[0].values.len(), 1);
248 assert!(matches!(
249 fields[0].values[0],
250 FieldValue::Base(BaseValue::Int(6416))
251 ));
252
253 assert_eq!(fields[1].name, "Float");
254 assert_eq!(fields[1].values.len(), 1);
255 assert!(matches!(
256 fields[1].values[0],
257 FieldValue::Base(BaseValue::Float(42.21))
258 ));
259
260 assert_eq!(fields[2].name, "ClassName");
261 assert_eq!(fields[2].values.len(), 1);
262 assert!(matches!(
263 fields[2].values[0],
264 FieldValue::WildcardPattern(_)
265 ));
266
267 assert_eq!(fields[3].name, "RandomID");
268 assert_eq!(fields[3].values.len(), 3);
269 assert!(matches!(
270 fields[3].values[0],
271 FieldValue::WildcardPattern(_)
272 ));
273
274 assert!(matches!(
275 fields[3].modifier.match_modifier,
276 Some(MatchModifier::Contains)
277 ));
278 }
279 Selection::Keyword(_) => {
280 panic!("wrong mode")
281 }
282 }
283 }
284}