dfirtk_eventdata/
process_id.rs

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