dfirtk_sessionevent_derive/
lib.rs1use 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}