misp_client/
events.rs

1//! MISP event operations and search queries.
2
3use serde_json::{json, Value};
4use tracing::debug;
5
6use crate::client::MispClient;
7use crate::error::MispError;
8use crate::models::{Attribute, Event, Galaxy, Tag};
9
10#[derive(Clone)]
11pub struct EventsClient {
12    client: MispClient,
13}
14
15impl EventsClient {
16    pub fn new(client: MispClient) -> Self {
17        Self { client }
18    }
19
20    pub async fn get(&self, id: &str) -> Result<Event, MispError> {
21        debug!(%id, "Fetching event");
22        let resp = self.client.get(&format!("/events/view/{}", id)).await?;
23        parse_event_response(resp)
24    }
25
26    pub async fn get_by_uuid(&self, uuid: &str) -> Result<Event, MispError> {
27        self.get(uuid).await
28    }
29
30    pub async fn index(&self, params: Option<EventIndexParams>) -> Result<Vec<Event>, MispError> {
31        debug!("Listing events");
32        let body = params.map(|p| p.to_json());
33        let resp = self.client.post("/events/index", body).await?;
34        parse_events_list(resp)
35    }
36
37    pub async fn search(&self, query: EventSearchQuery) -> Result<Vec<Event>, MispError> {
38        debug!("Searching events");
39        let resp = self
40            .client
41            .post("/events/restSearch", Some(query.to_json()))
42            .await?;
43        parse_rest_search_events(resp)
44    }
45
46    pub async fn get_tags(&self, event_id: &str) -> Result<Vec<Tag>, MispError> {
47        let event = self.get(event_id).await?;
48        Ok(event.tags)
49    }
50
51    pub async fn get_attributes(&self, event_id: &str) -> Result<Vec<Attribute>, MispError> {
52        let event = self.get(event_id).await?;
53        Ok(event.attributes)
54    }
55
56    pub async fn get_galaxies(&self, event_id: &str) -> Result<Vec<Galaxy>, MispError> {
57        let event = self.get(event_id).await?;
58        Ok(event.galaxies)
59    }
60}
61
62impl std::fmt::Debug for EventsClient {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.debug_struct("EventsClient").finish()
65    }
66}
67
68#[derive(Debug, Default, Clone)]
69pub struct EventIndexParams {
70    pub limit: Option<u32>,
71    pub page: Option<u32>,
72    pub sort: Option<String>,
73    pub direction: Option<String>,
74    pub minimal: Option<bool>,
75    pub published: Option<bool>,
76    pub org: Option<String>,
77    pub tags: Option<Vec<String>>,
78    pub from: Option<String>,
79    pub to: Option<String>,
80}
81
82impl EventIndexParams {
83    pub fn new() -> Self {
84        Self::default()
85    }
86
87    pub fn limit(mut self, limit: u32) -> Self {
88        self.limit = Some(limit);
89        self
90    }
91
92    pub fn page(mut self, page: u32) -> Self {
93        self.page = Some(page);
94        self
95    }
96
97    pub fn published(mut self, published: bool) -> Self {
98        self.published = Some(published);
99        self
100    }
101
102    pub fn tags(mut self, tags: Vec<String>) -> Self {
103        self.tags = Some(tags);
104        self
105    }
106
107    pub fn from_date(mut self, from: impl Into<String>) -> Self {
108        self.from = Some(from.into());
109        self
110    }
111
112    pub fn to_date(mut self, to: impl Into<String>) -> Self {
113        self.to = Some(to.into());
114        self
115    }
116
117    fn to_json(&self) -> Value {
118        let mut obj = serde_json::Map::new();
119        if let Some(v) = self.limit {
120            obj.insert("limit".into(), json!(v));
121        }
122        if let Some(v) = self.page {
123            obj.insert("page".into(), json!(v));
124        }
125        if let Some(ref v) = self.sort {
126            obj.insert("sort".into(), json!(v));
127        }
128        if let Some(ref v) = self.direction {
129            obj.insert("direction".into(), json!(v));
130        }
131        if let Some(v) = self.minimal {
132            obj.insert("minimal".into(), json!(v));
133        }
134        if let Some(v) = self.published {
135            obj.insert("published".into(), json!(v));
136        }
137        if let Some(ref v) = self.org {
138            obj.insert("org".into(), json!(v));
139        }
140        if let Some(ref v) = self.tags {
141            obj.insert("tags".into(), json!(v));
142        }
143        if let Some(ref v) = self.from {
144            obj.insert("from".into(), json!(v));
145        }
146        if let Some(ref v) = self.to {
147            obj.insert("to".into(), json!(v));
148        }
149        Value::Object(obj)
150    }
151}
152
153#[derive(Debug, Default, Clone)]
154pub struct EventSearchQuery {
155    pub value: Option<String>,
156    pub event_id: Option<String>,
157    pub tags: Option<Vec<String>>,
158    pub not_tags: Option<Vec<String>>,
159    pub org: Option<String>,
160    pub from: Option<String>,
161    pub to: Option<String>,
162    pub last: Option<String>,
163    pub published: Option<bool>,
164    pub threat_level: Option<Vec<u8>>,
165    pub analysis: Option<Vec<u8>>,
166    pub include_attribute: Option<bool>,
167    pub include_galaxy: Option<bool>,
168    pub limit: Option<u32>,
169    pub page: Option<u32>,
170}
171
172impl EventSearchQuery {
173    pub fn new() -> Self {
174        Self::default()
175    }
176
177    pub fn value(mut self, v: impl Into<String>) -> Self {
178        self.value = Some(v.into());
179        self
180    }
181
182    pub fn event_id(mut self, id: impl Into<String>) -> Self {
183        self.event_id = Some(id.into());
184        self
185    }
186
187    pub fn tags(mut self, tags: Vec<String>) -> Self {
188        self.tags = Some(tags);
189        self
190    }
191
192    pub fn exclude_tags(mut self, tags: Vec<String>) -> Self {
193        self.not_tags = Some(tags);
194        self
195    }
196
197    pub fn org(mut self, org: impl Into<String>) -> Self {
198        self.org = Some(org.into());
199        self
200    }
201
202    pub fn from_date(mut self, from: impl Into<String>) -> Self {
203        self.from = Some(from.into());
204        self
205    }
206
207    pub fn to_date(mut self, to: impl Into<String>) -> Self {
208        self.to = Some(to.into());
209        self
210    }
211
212    pub fn last(mut self, duration: impl Into<String>) -> Self {
213        self.last = Some(duration.into());
214        self
215    }
216
217    pub fn published(mut self, published: bool) -> Self {
218        self.published = Some(published);
219        self
220    }
221
222    pub fn threat_level(mut self, levels: Vec<u8>) -> Self {
223        self.threat_level = Some(levels);
224        self
225    }
226
227    pub fn include_attributes(mut self) -> Self {
228        self.include_attribute = Some(true);
229        self
230    }
231
232    pub fn include_galaxies(mut self) -> Self {
233        self.include_galaxy = Some(true);
234        self
235    }
236
237    pub fn limit(mut self, limit: u32) -> Self {
238        self.limit = Some(limit);
239        self
240    }
241
242    pub fn page(mut self, page: u32) -> Self {
243        self.page = Some(page);
244        self
245    }
246
247    fn to_json(&self) -> Value {
248        let mut obj = serde_json::Map::new();
249        if let Some(ref v) = self.value {
250            obj.insert("value".into(), json!(v));
251        }
252        if let Some(ref v) = self.event_id {
253            obj.insert("eventid".into(), json!(v));
254        }
255        if let Some(ref v) = self.tags {
256            obj.insert("tags".into(), json!(v));
257        }
258        if let Some(ref v) = self.not_tags {
259            obj.insert("not_tags".into(), json!(v));
260        }
261        if let Some(ref v) = self.org {
262            obj.insert("org".into(), json!(v));
263        }
264        if let Some(ref v) = self.from {
265            obj.insert("from".into(), json!(v));
266        }
267        if let Some(ref v) = self.to {
268            obj.insert("to".into(), json!(v));
269        }
270        if let Some(ref v) = self.last {
271            obj.insert("last".into(), json!(v));
272        }
273        if let Some(v) = self.published {
274            obj.insert("published".into(), json!(v));
275        }
276        if let Some(ref v) = self.threat_level {
277            obj.insert("threat_level_id".into(), json!(v));
278        }
279        if let Some(ref v) = self.analysis {
280            obj.insert("analysis".into(), json!(v));
281        }
282        if let Some(v) = self.include_attribute {
283            obj.insert("includeAttribute".into(), json!(v));
284        }
285        if let Some(v) = self.include_galaxy {
286            obj.insert("includeGalaxy".into(), json!(v));
287        }
288        if let Some(v) = self.limit {
289            obj.insert("limit".into(), json!(v));
290        }
291        if let Some(v) = self.page {
292            obj.insert("page".into(), json!(v));
293        }
294        Value::Object(obj)
295    }
296}
297
298fn parse_event_response(resp: Value) -> Result<Event, MispError> {
299    if let Some(event) = resp.get("Event") {
300        return serde_json::from_value(event.clone()).map_err(MispError::Parse);
301    }
302    Err(MispError::InvalidResponse("missing Event wrapper".into()))
303}
304
305fn parse_events_list(resp: Value) -> Result<Vec<Event>, MispError> {
306    if let Some(arr) = resp.as_array() {
307        let events: Result<Vec<Event>, _> = arr
308            .iter()
309            .map(|v| {
310                let event_val = v.get("Event").unwrap_or(v);
311                serde_json::from_value(event_val.clone())
312            })
313            .collect();
314        return events.map_err(MispError::Parse);
315    }
316    Err(MispError::InvalidResponse("expected array".into()))
317}
318
319fn parse_rest_search_events(resp: Value) -> Result<Vec<Event>, MispError> {
320    if let Some(response) = resp.get("response") {
321        if let Some(arr) = response.as_array() {
322            let events: Result<Vec<Event>, _> = arr
323                .iter()
324                .map(|v| {
325                    let event_val = v.get("Event").unwrap_or(v);
326                    serde_json::from_value(event_val.clone())
327                })
328                .collect();
329            return events.map_err(MispError::Parse);
330        }
331    }
332    if resp.as_array().is_some() {
333        return parse_events_list(resp);
334    }
335    Err(MispError::InvalidResponse(
336        "unexpected response format".into(),
337    ))
338}