dfirtk_sessionevent_derive/
lib.rs

1use darling::FromDeriveInput;
2use dfirtk_eventdata::{EventProvider, EventId};
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput};
6
7mod session_id_type;
8use session_id_type::*;
9
10#[derive(FromDeriveInput)]
11#[darling(attributes(event_data))]
12struct EventStructOptions {
13    provider: EventProvider,
14    event_id: EventId,
15    description: String,
16    session_id: SessionIdType,
17    username_path: Option<String>,
18    domain_path: Option<String>,
19    client_hostname_path: Option<String>,
20    client_address_path: Option<String>,
21    server_hostname_path: Option<String>,
22    server_address_path: Option<String>,
23}
24
25fn create_getter(path: &Option<String>, function_name: TokenStream) -> TokenStream {
26    match path {
27        None => quote!(
28            fn #function_name (&self, _: &SerializedEvtxRecord<Value>) -> Option<String> {
29                None
30            }),
31        Some(path) => {
32            let parts: Vec<_> = path.split('/').map(|part| quote!([#part])).collect();
33            quote!(
34                fn #function_name (&self, record: &SerializedEvtxRecord<Value>) -> Option<String> {
35                    record.data #(#parts)* .as_str().map(|s|s.to_owned())
36                })
37        }
38    }
39}
40
41#[proc_macro_derive(SessionEvent, attributes(event_data))]
42pub fn derive_session_event(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
43    let input = parse_macro_input!(input as DeriveInput);
44    let opts = EventStructOptions::from_derive_input(&input).expect("Wrong options");
45    let name = input.ident;
46
47    let provider = opts.provider;
48    let event_id = opts.event_id;
49    let description = opts.description;
50    let session_id_type = opts.session_id;
51
52    let username_getter = create_getter(&opts.username_path, quote!(username));
53    let domain_getter = create_getter(&opts.domain_path, quote!(domain));
54    let client_hostname_getter = create_getter(&opts.client_hostname_path, quote!(client_hostname));
55    let client_address_getter = create_getter(&opts.client_address_path, quote!(client_address));
56    let server_hostname_getter = create_getter(&opts.server_hostname_path, quote!(server_hostname));
57    let server_address_getter = create_getter(&opts.server_address_path, quote!(server_address));
58
59    let expanded = quote! {
60        impl SessionEventInfo for #name {
61            fn event_id(&self) -> EventId {
62                #event_id
63            }
64            fn description(&self) -> &'static str {
65                #description
66            }
67            fn provider(&self) -> EventProvider {
68                #provider
69            }
70            fn generate_id(&self, record: &SerializedEvtxRecord<Value>) -> dfirtk_eventdata::SessionId {
71                #session_id_type::session_id_of(record)
72            }
73            #username_getter
74            #domain_getter
75            #client_hostname_getter
76            #client_address_getter
77            #server_hostname_getter
78            #server_address_getter
79        }
80    };
81
82    proc_macro::TokenStream::from(expanded)
83}