@@ -22,7 +22,6 @@ use std::{
22
22
} ;
23
23
24
24
use crate :: about:: current;
25
- use crate :: handlers:: http:: modal:: utils:: rbac_utils:: get_metadata;
26
25
27
26
use super :: option:: CONFIG ;
28
27
use chrono:: { DateTime , Utc } ;
@@ -101,10 +100,22 @@ pub enum AuditLogVersion {
101
100
V1 = 1 ,
102
101
}
103
102
103
+ #[ derive( Serialize ) ]
104
+ pub struct AuditDetails {
105
+ pub version : AuditLogVersion ,
106
+ pub id : Ulid ,
107
+ pub generated_at : DateTime < Utc > ,
108
+ }
109
+
110
+ #[ derive( Serialize ) ]
111
+ pub struct ServerDetails {
112
+ pub version : String ,
113
+ pub deployment_id : Ulid ,
114
+ }
115
+
104
116
// Contains information about the actor (user) who performed the action
105
117
#[ derive( Serialize , Default ) ]
106
- #[ serde( rename_all = "camelCase" ) ]
107
- pub struct ActorLog {
118
+ pub struct ActorDetails {
108
119
pub remote_host : String ,
109
120
pub user_agent : String ,
110
121
pub username : String ,
@@ -113,7 +124,10 @@ pub struct ActorLog {
113
124
114
125
// Contains details about the HTTP request that was made
115
126
#[ derive( Serialize , Default ) ]
116
- pub struct RequestLog {
127
+ pub struct RequestDetails {
128
+ pub stream : String ,
129
+ pub start_time : DateTime < Utc > ,
130
+ pub end_time : DateTime < Utc > ,
117
131
pub method : String ,
118
132
pub path : String ,
119
133
pub protocol : String ,
@@ -122,45 +136,34 @@ pub struct RequestLog {
122
136
123
137
/// Contains information about the response sent back to the client
124
138
#[ derive( Default , Serialize ) ]
125
- #[ serde( rename_all = "camelCase" ) ]
126
- pub struct ResponseLog {
139
+ pub struct ResponseDetails {
127
140
pub status_code : u16 ,
128
141
pub error : Option < String > ,
129
142
}
130
143
131
144
/// The main audit log structure that combines all audit information
132
145
#[ derive( Serialize ) ]
133
- #[ serde( rename_all = "camelCase" ) ]
134
146
pub struct AuditLog {
135
- pub version : AuditLogVersion ,
136
- pub parseable_version : String ,
137
- pub deployment_id : Ulid ,
138
- pub audit_id : Ulid ,
139
- pub start_time : DateTime < Utc > ,
140
- pub end_time : DateTime < Utc > ,
141
- pub stream : String ,
142
- pub actor : ActorLog ,
143
- pub request : RequestLog ,
144
- pub response : ResponseLog ,
147
+ pub audit : AuditDetails ,
148
+ pub parseable_server : ServerDetails ,
149
+ pub actor : ActorDetails ,
150
+ pub request : RequestDetails ,
151
+ pub response : ResponseDetails ,
145
152
}
146
153
147
154
/// Builder pattern implementation for constructing audit logs
148
155
pub struct AuditLogBuilder {
149
156
// Used to ensure that log is only constructed if the logger is enabled
150
157
enabled : bool ,
151
- start_time : DateTime < Utc > ,
152
- stream : String ,
153
- pub actor : Option < ActorLog > ,
154
- pub request : Option < RequestLog > ,
155
- pub response : Option < ResponseLog > ,
158
+ pub actor : Option < ActorDetails > ,
159
+ pub request : Option < RequestDetails > ,
160
+ pub response : Option < ResponseDetails > ,
156
161
}
157
162
158
163
impl Default for AuditLogBuilder {
159
164
fn default ( ) -> Self {
160
165
AuditLogBuilder {
161
166
enabled : AUDIT_LOGGER . is_some ( ) ,
162
- start_time : Utc :: now ( ) ,
163
- stream : String :: default ( ) ,
164
167
actor : None ,
165
168
request : None ,
166
169
response : None ,
@@ -169,91 +172,159 @@ impl Default for AuditLogBuilder {
169
172
}
170
173
171
174
impl AuditLogBuilder {
172
- /// Sets the stream name for the audit log if logger is set
173
- pub fn set_stream_name ( mut self , stream : impl Into < String > ) -> Self {
174
- if !self . enabled {
175
- return self ;
175
+ /// Sets the remote host for the audit log
176
+ pub fn with_host ( mut self , host : impl Into < String > ) -> Self {
177
+ if self . enabled {
178
+ self . actor
179
+ . get_or_insert_with ( ActorDetails :: default)
180
+ . remote_host = host. into ( ) ;
176
181
}
177
- self . stream = stream. into ( ) ;
182
+ self
183
+ }
178
184
185
+ /// Sets the username for the audit log
186
+ pub fn with_username ( mut self , username : impl Into < String > ) -> Self {
187
+ if self . enabled {
188
+ self . actor
189
+ . get_or_insert_with ( ActorDetails :: default)
190
+ . username = username. into ( ) ;
191
+ }
179
192
self
180
193
}
181
194
182
- /// Sets the actor details for the audit log if logger is set
183
- pub fn set_actor (
184
- mut self ,
185
- host : impl Into < String > ,
186
- username : impl Into < String > ,
187
- user_agent : impl Into < String > ,
188
- auth_method : impl Into < String > ,
189
- ) -> Self {
190
- if !self . enabled {
191
- return self ;
195
+ /// Sets the user agent for the audit log
196
+ pub fn with_user_agent ( mut self , user_agent : impl Into < String > ) -> Self {
197
+ if self . enabled {
198
+ self . actor
199
+ . get_or_insert_with ( ActorDetails :: default)
200
+ . user_agent = user_agent. into ( ) ;
192
201
}
193
- self . actor = Some ( ActorLog {
194
- remote_host : host. into ( ) ,
195
- user_agent : user_agent. into ( ) ,
196
- username : username. into ( ) ,
197
- authorization_method : auth_method. into ( ) ,
198
- } ) ;
202
+ self
203
+ }
199
204
205
+ /// Sets the authorization method for the audit log
206
+ pub fn with_auth_method ( mut self , auth_method : impl Into < String > ) -> Self {
207
+ if self . enabled {
208
+ self . actor
209
+ . get_or_insert_with ( ActorDetails :: default)
210
+ . authorization_method = auth_method. into ( ) ;
211
+ }
200
212
self
201
213
}
202
214
203
- /// Sets the request details for the audit log if logger is set
204
- pub fn set_request (
205
- mut self ,
206
- method : impl Into < String > ,
207
- path : impl Into < String > ,
208
- protocol : impl Into < String > ,
209
- headers : impl IntoIterator < Item = ( String , String ) > ,
210
- ) -> Self {
211
- if !self . enabled {
212
- return self ;
215
+ /// Sets the stream for the request details
216
+ pub fn with_stream ( mut self , stream : impl Into < String > ) -> Self {
217
+ if self . enabled {
218
+ self . request
219
+ . get_or_insert_with ( RequestDetails :: default)
220
+ . stream = stream. into ( ) ;
213
221
}
214
- self . request = Some ( RequestLog {
215
- method : method. into ( ) ,
216
- path : path. into ( ) ,
217
- protocol : protocol. into ( ) ,
218
- headers : headers. into_iter ( ) . collect ( ) ,
219
- } ) ;
222
+ self
223
+ }
220
224
225
+ /// Sets the request timing details
226
+ pub fn with_timing ( mut self , start_time : DateTime < Utc > , end_time : DateTime < Utc > ) -> Self {
227
+ if self . enabled {
228
+ let request = self . request . get_or_insert_with ( RequestDetails :: default) ;
229
+ request. start_time = start_time;
230
+ request. end_time = end_time;
231
+ }
221
232
self
222
233
}
223
234
224
- /// Sets the response details for the audit log if logger is set
225
- pub fn set_response ( mut self , status_code : u16 , err : impl Display ) -> Self {
226
- if !self . enabled {
227
- return self ;
235
+ /// Sets the request method details
236
+ pub fn with_method ( mut self , method : impl Into < String > ) -> Self {
237
+ if self . enabled {
238
+ self . request
239
+ . get_or_insert_with ( RequestDetails :: default)
240
+ . method = method. into ( ) ;
228
241
}
229
- let error = err. to_string ( ) ;
230
- let error = ( !error. is_empty ( ) ) . then_some ( error) ;
231
- self . response = Some ( ResponseLog { status_code, error } ) ;
242
+ self
243
+ }
244
+
245
+ /// Sets the request path
246
+ pub fn with_path ( mut self , path : impl Into < String > ) -> Self {
247
+ if self . enabled {
248
+ self . request
249
+ . get_or_insert_with ( RequestDetails :: default)
250
+ . path = path. into ( ) ;
251
+ }
252
+ self
253
+ }
254
+
255
+ /// Sets the request protocol
256
+ pub fn with_protocol ( mut self , protocol : impl Into < String > ) -> Self {
257
+ if self . enabled {
258
+ self . request
259
+ . get_or_insert_with ( RequestDetails :: default)
260
+ . protocol = protocol. into ( ) ;
261
+ }
262
+ self
263
+ }
264
+
265
+ /// Sets the request headers
266
+ pub fn with_headers ( mut self , headers : impl IntoIterator < Item = ( String , String ) > ) -> Self {
267
+ if self . enabled {
268
+ self . request
269
+ . get_or_insert_with ( RequestDetails :: default)
270
+ . headers = headers. into_iter ( ) . collect ( ) ;
271
+ }
272
+ self
273
+ }
232
274
275
+ /// Sets the response status code
276
+ pub fn with_status ( mut self , status_code : u16 ) -> Self {
277
+ if self . enabled {
278
+ self . response
279
+ . get_or_insert_with ( ResponseDetails :: default)
280
+ . status_code = status_code;
281
+ }
282
+ self
283
+ }
284
+
285
+ /// Sets the response error if any
286
+ pub fn with_error ( mut self , err : impl Display ) -> Self {
287
+ if self . enabled {
288
+ let error = err. to_string ( ) ;
289
+ if !error. is_empty ( ) {
290
+ self . response
291
+ . get_or_insert_with ( ResponseDetails :: default)
292
+ . error = Some ( error) ;
293
+ }
294
+ }
233
295
self
234
296
}
235
297
236
298
/// Sends the audit log to the logging server if configured
237
299
pub async fn send ( self ) {
300
+ // ensures that we don't progress if logger is not enabled
301
+ if !self . enabled {
302
+ return ;
303
+ }
304
+
305
+ // build the audit log
238
306
let AuditLogBuilder {
239
- start_time,
240
- stream,
241
307
actor,
242
308
request,
243
309
response,
244
310
..
245
311
} = self ;
246
- let Some ( logger) = AUDIT_LOGGER . as_ref ( ) else {
247
- return ;
248
- } ;
312
+
313
+ // get the logger
314
+ let logger = AUDIT_LOGGER . as_ref ( ) . unwrap ( ) ;
315
+
316
+ // build the audit log
317
+ let now = Utc :: now ( ) ;
249
318
let audit_log = AuditLog {
250
- version : AuditLogVersion :: V1 ,
251
- parseable_version : current ( ) . released_version . to_string ( ) ,
252
- deployment_id : get_metadata ( ) . await . unwrap ( ) . deployment_id ,
253
- audit_id : Ulid :: new ( ) ,
254
- start_time,
255
- end_time : Utc :: now ( ) ,
256
- stream,
319
+ audit : AuditDetails {
320
+ version : AuditLogVersion :: V1 ,
321
+ id : Ulid :: new ( ) ,
322
+ generated_at : now,
323
+ } ,
324
+ parseable_server : ServerDetails {
325
+ version : current ( ) . released_version . to_string ( ) ,
326
+ deployment_id : Ulid :: new ( ) ,
327
+ } ,
257
328
actor : actor. unwrap_or_default ( ) ,
258
329
request : request. unwrap_or_default ( ) ,
259
330
response : response. unwrap_or_default ( ) ,
0 commit comments