more audit logging
parent
8419871428
commit
4ec5d66d25
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue