more audit logging

main
_ 2021-04-28 20:18:53 -05:00
parent 8419871428
commit 4ec5d66d25
3 changed files with 54 additions and 11 deletions

View File

@ -123,7 +123,9 @@ async fn handle_http_request (
} }
} }
let req = match http_serde::RequestParts::from_hyper (req.method, uri, req.headers) { let user = req.headers.get ("X-Email").map (|x| Some (x.to_str ().ok ()?.to_string ())).flatten ();
let req = match http_serde::RequestParts::from_hyper (req.method, uri.clone (), req.headers) {
Ok (x) => x, Ok (x) => x,
Err (_) => return Err (BadRequest), Err (_) => return Err (BadRequest),
}; };
@ -133,8 +135,10 @@ async fn handle_http_request (
let req_id = rusty_ulid::generate_ulid_string (); let req_id = rusty_ulid::generate_ulid_string ();
state.audit_log.push (AuditEvent::new (AuditData::WebClientGet { state.audit_log.push (AuditEvent::new (AuditData::WebClientGet {
user,
req_id: req_id.clone (), req_id: req_id.clone (),
server_name: server_name.to_string (), server_name: server_name.to_string (),
uri,
})).await; })).await;
trace! ("Created request {}", req_id); trace! ("Created request {}", req_id);
@ -196,6 +200,28 @@ enum LastSeen {
Description (String), Description (String),
} }
fn pretty_print_utc (
now: DateTime <Utc>,
last_seen: DateTime <Utc>
) -> String
{
let dur = now.signed_duration_since (last_seen);
if dur < chrono::Duration::zero () {
return last_seen.to_rfc3339_opts (SecondsFormat::Secs, true);
}
if dur.num_minutes () < 1 {
return format! ("{} s ago", dur.num_seconds ());
}
if dur.num_hours () < 1 {
return format! ("{} m ago", dur.num_minutes ());
}
last_seen.to_rfc3339_opts (SecondsFormat::Secs, true)
}
// Mnemonic is "now - last_seen" // Mnemonic is "now - last_seen"
fn pretty_print_last_seen ( fn pretty_print_last_seen (
@ -258,7 +284,13 @@ struct UnregisteredServer {
#[derive (Serialize)] #[derive (Serialize)]
struct AuditLogPage { struct AuditLogPage {
audit_log: Vec <String>, audit_log: Vec <AuditEntryPretty>,
}
#[derive (Serialize)]
struct AuditEntryPretty {
utc_pretty: String,
data_pretty: String,
} }
async fn handle_server_list_internal (state: &Arc <Relay>) async fn handle_server_list_internal (state: &Arc <Relay>)
@ -350,8 +382,14 @@ async fn handle_unregistered_servers_internal (state: &Arc <Relay>)
async fn handle_audit_log_internal (state: &Arc <Relay>) async fn handle_audit_log_internal (state: &Arc <Relay>)
-> AuditLogPage -> AuditLogPage
{ {
let utc_now = Utc::now ();
let audit_log = state.audit_log.to_vec ().await let audit_log = state.audit_log.to_vec ().await
.iter ().rev ().map (|e| format! ("{:?}", e)).collect (); .iter ().rev ().map (|e| {
AuditEntryPretty {
utc_pretty: pretty_print_utc (utc_now, e.time_utc),
data_pretty: format! ("{:?}", e.data),
}
}).collect ();
AuditLogPage { AuditLogPage {
audit_log, audit_log,

View File

@ -89,10 +89,10 @@ pub struct Relay {
pub (crate) shutdown_watch_tx: watch::Sender <bool>, pub (crate) shutdown_watch_tx: watch::Sender <bool>,
pub (crate) shutdown_watch_rx: watch::Receiver <bool>, pub (crate) shutdown_watch_rx: watch::Receiver <bool>,
// List of recently rejected server names (Used to approve servers) /// List of recently rejected server names (Used to approve servers)
pub (crate) unregistered_servers: BoundedVec <RejectedServer>, pub (crate) unregistered_servers: BoundedVec <RejectedServer>,
// Memory backend for audit logging /// Memory backend for audit logging
// TODO: Add file / database / network server logging backend // TODO: Add file / database / network server logging backend
pub (crate) audit_log: BoundedVec <AuditEvent>, pub (crate) audit_log: BoundedVec <AuditEvent>,
} }
@ -107,16 +107,18 @@ pub struct RejectedServer {
#[derive (Clone, Debug)] #[derive (Clone, Debug)]
pub struct AuditEvent { pub struct AuditEvent {
time_monotonic: Instant, time_monotonic: Instant,
time_utc: DateTime <Utc>, pub time_utc: DateTime <Utc>,
data: AuditData, pub data: AuditData,
} }
#[derive (Clone, Debug)] #[derive (Clone, Debug)]
pub enum AuditData { pub enum AuditData {
RelayStart, RelayStart,
WebClientGet { WebClientGet {
user: Option <String>,
req_id: String, req_id: String,
server_name: String, server_name: String,
uri: String,
}, },
} }

View File

@ -40,22 +40,25 @@ AIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA" rel="icon" type="image/x-icon" />
<h1>Audit log</h1> <h1>Audit log</h1>
<p> <p>(Newest events at the top)</p>
(Newest events at the top)
<p>CSV link goes here</p>
<div style="padding-top: 1em;"> <div style="padding-top: 1em;">
{{#if audit_log}} {{#if audit_log}}
<table class="entry_list"> <table class="entry_list">
<thead> <thead>
<tr> <tr>
<th>Debug</th> <th>UTC</th>
<th>Data</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{#each audit_log}} {{#each audit_log}}
<tr> <tr>
<td><span>{{this}}</span></td> <td><span>{{this.utc_pretty}}</span></td>
<td><span>{{this.data_pretty}}</span></td>
</tr> </tr>
{{/each}} {{/each}}