dfirtk_eventdata/
event_id.rs

1use std::{
2    convert::{TryFrom, TryInto},
3    fmt::Display,
4};
5
6use anyhow::bail;
7use darling::FromMeta;
8use evtx::SerializedEvtxRecord;
9use quote::quote;
10use serde::Serialize;
11use serde_json::Value;
12
13use super::EvtxFieldView;
14
15#[derive(PartialEq, Eq, Clone, Debug, Serialize)]
16pub struct EventId(pub u16);
17
18impl TryFrom<&SerializedEvtxRecord<Value>> for EventId {
19    type Error = anyhow::Error;
20
21    fn try_from(record: &SerializedEvtxRecord<Value>) -> Result<Self, Self::Error> {
22        let event_id = &record.data["Event"]["System"]["EventID"];
23
24        let event_id = match event_id.get("#text") {
25            Some(eid) => eid,
26            None => event_id,
27        };
28
29        if let Some(event_id) = event_id.as_u64() {
30            let id: u16 = event_id.try_into()?;
31            Ok(Self(id))
32        } else {
33            bail!("event id cannot be converted to u16: {event_id}")
34        }
35    }
36}
37
38impl EventId {
39    pub fn value(&self) -> u16 {
40        self.0
41    }
42}
43
44const EVENT_ID_MAX_LENGTH: usize = 5;
45impl EvtxFieldView for EventId {
46    fn maximum_display_length(&self) -> usize {
47        EVENT_ID_MAX_LENGTH
48    }
49
50    fn value_with_padding(&self) -> String {
51        format!("{:5}", self.0)
52    }
53}
54
55impl From<EventId> for u16 {
56    fn from(me: EventId) -> Self {
57        me.0
58    }
59}
60
61impl From<u16> for EventId {
62    fn from(id: u16) -> Self {
63        Self(id)
64    }
65}
66
67impl Display for EventId {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        self.0.fmt(f)
70    }
71}
72
73impl FromMeta for EventId {
74    fn from_value(value: &darling::export::syn::Lit) -> darling::Result<Self> {
75        match value {
76            darling::export::syn::Lit::Int(lit) => Ok(Self::from(lit.base10_parse::<u16>()?)),
77            _ => Err(darling::Error::unknown_value("invalid event id")),
78        }
79    }
80}
81
82impl quote::ToTokens for EventId {
83    fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) {
84        let me = self.0;
85        tokens.extend(quote!(
86            {
87                use dfirtk_eventdata::EventId;
88                EventId(#me)
89            }
90        ))
91    }
92}