added audit logs in a format parsers can grab

This commit is contained in:
Artemis 2025-01-27 12:12:33 +01:00
parent f7da45312a
commit 322a90b62e
3 changed files with 80 additions and 20 deletions

View file

@ -1,3 +1,5 @@
use std::net::IpAddr;
use rocket::{
form::{self, Contextual, Error, Form},
http::CookieJar,
@ -64,6 +66,7 @@ pub async fn change_settings(
user: User,
meta: CommonTemplateState,
mut form: Form<Contextual<'_, CommonSettings<'_>>>,
client_ip: IpAddr,
) -> PageResult {
let values = match form.value {
Some(ref v) => v,
@ -110,6 +113,13 @@ pub async fn change_settings(
user::update_info(&mut *db, &user.id, new_username, new_email).await?;
info!(
"[audit|{}] [{}] changed username/email (account ID {})",
client_ip,
user.username,
user.id.to_string(),
);
Ok(Redirect::to(uri!("/account", show_settings)).into())
}
@ -138,6 +148,7 @@ pub async fn change_password(
user: User,
meta: CommonTemplateState,
mut form: Form<Contextual<'_, PasswordSettings<'_>>>,
client_ip: IpAddr,
) -> PageResult {
let values = match form.value {
Some(ref v) => v,
@ -178,6 +189,8 @@ pub async fn change_password(
let new_password_hash = task::spawn_blocking(move || pw::hash(&new_password)).await??;
user::update_password(&mut *db, &user.id, &new_password_hash).await?;
info!("[audit|{}] [{}] changed password", client_ip, user.username);
Ok(Redirect::to(uri!("/account", show_settings)).into())
}
@ -190,10 +203,16 @@ pub struct DataDump {
}
#[get("/data_dump")]
pub async fn export_data(mut db: DollTagsDb, user: User) -> RawResult<Json<DataDump>> {
pub async fn export_data(
mut db: DollTagsDb,
user: User,
client_ip: IpAddr,
) -> RawResult<Json<DataDump>> {
let tags = doll::list(&mut *db, &user.id).await?;
let reserved_tags = doll::list_archived(&mut *db, &user.id).await?;
info!("[audit|{}] [{}] exported data", client_ip, user.username);
Ok(Json(DataDump {
account: user,
tags,
@ -225,10 +244,21 @@ pub async fn ask_delete(
}
#[get("/yes_delete_this/<id>")]
pub async fn confirm_delete(mut db: DollTagsDb, id: i32, _user: User) -> PageResult {
pub async fn confirm_delete(
mut db: DollTagsDb,
id: i32,
user: User,
client_ip: IpAddr,
) -> PageResult {
let mut trx = db.begin().await?;
doll::delete(&mut trx, id).await?;
trx.commit().await?;
info!(
"[audit|{}] [{}] deleted tag {:0>6}",
client_ip, user.username, id
);
Ok(Redirect::to(uri!("/account", index)).into())
}
@ -242,6 +272,7 @@ pub async fn confirm_terminate_account(
mut db: DollTagsDb,
user: User,
cookies: &CookieJar<'_>,
client_ip: IpAddr,
) -> PageResult {
let mut trx = db.begin().await?;
doll::delete_all_from_account(&mut trx, &user.id).await?;
@ -249,5 +280,7 @@ pub async fn confirm_terminate_account(
session::logout(cookies);
trx.commit().await?;
info!("[audit|{}] [{}] deleted account", client_ip, user.username);
Ok(Redirect::to("/").into())
}

View file

@ -1,3 +1,5 @@
use std::net::IpAddr;
use regex::Regex;
use rocket::{
form::{self, Contextual, Form},
@ -49,24 +51,32 @@ pub async fn handle_login(
cookies: &CookieJar<'_>,
maybe_loggedin: Option<User>,
meta: CommonTemplateState,
client_ip: IpAddr,
) -> PageResult {
if maybe_loggedin.is_some() {
let next = String::from(next.unwrap_or("/"));
return Ok(Redirect::to(next).into());
}
let miss = || {
PageResponse::Page(Template::render(
"account/login",
context! {failure: true, meta},
))
};
let values = match &form.value {
None => return Ok(miss()),
None => {
return Ok(Template::render("account/login", context! {failure: true, meta}).into())
}
Some(v) => v,
};
let miss = (|username: String| {
move || {
info!("[audit|{}] [{}] login failure", client_ip, username);
PageResponse::Page(Template::render(
"account/login",
context! {failure: true, meta},
))
}
})(String::from(values.username));
info!("[audit|{}] [{}] login attempt", client_ip, &values.username);
let user_in_db = user::get(db, &values.username).await?;
let user = match user_in_db {
None => return Ok(miss()),
@ -79,6 +89,10 @@ pub async fn handle_login(
if right_password && user.enabled {
session::login(cookies, &user.id);
info!(
"[audit|{}] [{}] login successful",
client_ip, &values.username
);
let next_url = String::from(next.unwrap_or("/"));
Ok(Redirect::to(next_url).into())
} else {
@ -137,6 +151,7 @@ pub async fn handle_register(
cookies: &CookieJar<'_>,
maybe_loggedin: Option<User>,
meta: CommonTemplateState,
client_ip: IpAddr,
) -> PageResult {
if maybe_loggedin.is_some() {
return Ok(Redirect::to("/").into());
@ -161,11 +176,6 @@ pub async fn handle_register(
}
};
debug!(
"registering account {} ({:?})",
values.username, values.email
);
let password = String::from(values.password);
let hashed_password = task::spawn_blocking(move || pw::hash(&password)).await??;
@ -181,6 +191,10 @@ pub async fn handle_register(
)
.await?;
info!(
"[audit|{}] [{}] account creation",
client_ip, &values.username
);
session::login(cookies, &account_id);
Ok(Redirect::to(uri!("/")).into())

View file

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, net::IpAddr};
use rocket::{
form::{self, Contextual, Form},
@ -172,6 +172,7 @@ pub async fn handle_register(
tag: Form<Contextual<'_, TagForm<'_>>>,
user: User,
meta: CommonTemplateState,
client_ip: IpAddr,
) -> PageResult {
let tag = match tag.value {
Some(ref values) => values,
@ -194,7 +195,6 @@ pub async fn handle_register(
}
};
debug!("registering tag: {:?}", tag);
fn normalize_opt(opt: &str) -> Option<&str> {
if opt.len() != 0 {
Some(opt)
@ -208,10 +208,11 @@ pub async fn handle_register(
let microchip_id = normalize_opt(&normalized_microchip_id);
if doll::id_exists(&mut *db, id, microchip_id.unwrap_or("")).await? {
// TODO: that's weird... what was i expecting to do here?
return Ok(Redirect::found(uri!("/account", show_register)).into());
}
doll::create(
let creation_status = doll::create(
&mut *db,
CreateDollProfile {
id,
@ -232,7 +233,20 @@ pub async fn handle_register(
bound_to_id: &user.id,
},
)
.await?;
.await;
if creation_status.is_err() {
info!(
"[audit|{}] [{}] failed to register tag {}",
client_ip, user.username, tag.ident
);
}
creation_status?;
info!(
"[audit|{}] [{}] registered tag {}",
client_ip, user.username, tag.ident
);
Ok(Redirect::to(uri!(public::show_profile(Some(tag.ident), microchip_id))).into())
}
@ -267,7 +281,6 @@ pub async fn handle_edit_tag(
}
};
debug!("editing tag: {:?}", tag);
fn normalize_opt(opt: &str) -> Option<&str> {
if opt.len() != 0 {
Some(opt)