Add ban check and reason retrieval for user authentication

- Introduced `check_ban` and `get_ban_reason` functions in `db::users`
- Updated client handler to enforce ban checks during login
- Added detailed logging for ban status and reasons
This commit is contained in:
Andrea Moro 2025-04-21 18:36:30 +02:00
parent b98a890738
commit d06a15771a
4 changed files with 103 additions and 1 deletions

BIN
db.sqlite

Binary file not shown.

Binary file not shown.

View file

@ -4,7 +4,9 @@ pub(crate) mod handlers {
Aes256Gcm, Key, Nonce,
};
use crate::db::users::{check_for_account, create_user, hash_password, verify_password};
use crate::db::users::{
check_ban, check_for_account, create_user, get_ban_reason, hash_password, verify_password,
};
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use log::{debug, error, info};
use serde::Deserialize;
@ -89,6 +91,38 @@ pub(crate) mod handlers {
// Check if the user already exists in the database
if check_for_account(&username).await? {
// Check if the user is banned
if check_ban(&username).await? == true {
let ban_reason_result = get_ban_reason(&username).await;
let message: String = match ban_reason_result {
Ok(Some(reason)) => {
info!("User {} is banned, Reason: {}", username, reason);
format!("User {} is banned, Reason: {}", username, reason).to_string()
}
Ok(None) => {
info!("User {} is banned, but no reason provided", username);
format!("User {} is banned, but no reason provided", username).to_string()
}
Err(e) => {
error!("Error fetching ban reason: {}", e);
format!("You are banned").to_string();
return Ok(());
}
};
let encrypted = match cipher_writer.encrypt(&nonce_writer, message.as_bytes()) {
Ok(encrypted) => encrypted,
Err(e) => {
error!("Encryption error: {}", e);
return Ok(());
}
};
let message = format!("{}\n", BASE64.encode(&encrypted));
writer.write_all(message.as_bytes()).await?;
return Ok(());
}
info!("User {} already exists", username);
// Send a message to the client
let message = format!("User {} is registered, input your password", username);

View file

@ -93,6 +93,74 @@ pub(crate) mod users {
password_hash.to_string()
}
pub async fn check_ban(username: &str) -> Result<bool, sqlx::Error> {
let pool = create_db_pool().await?;
let is_banned = sqlx::query(
r#"
SELECT EXISTS(
SELECT 1
FROM users
WHERE username = ?
)
"#,
)
.bind(username)
.fetch_one(&pool)
.await?
.get::<i64, _>(0);
// Check if the user is banned
if is_banned == 1 {
info!("User {} is banned", username);
} else {
info!("User {} is not banned", username);
}
Ok(is_banned == 1)
}
pub async fn get_ban_reason(username: &str) -> Result<Option<String>, sqlx::Error> {
let pool = create_db_pool().await?;
info!("Attempting to fetch ban reason for user: {}", username);
let row_option = sqlx::query(
r#"
SELECT ban_reason
FROM users
WHERE username = ?
"#,
)
.bind(username)
.fetch_optional(&pool)
.await?;
// Process the result
match row_option {
Some(row) => {
// Row found, now get the ban_reason (which might be NULL)
let reason: Option<String> = row.get(0); // Type annotation clarifies intent
if let Some(ref r) = reason {
info!("User {} found. Ban reason: {}", username, r);
} else {
// User exists, but ban_reason is NULL in the database
info!(
"User {} found, but ban_reason is NULL (not banned)",
username
);
}
Ok(reason)
}
None => {
// No row found for the username
info!("User {} not found in the database", username);
// Return Ok(None) as per the function signature, indicating no ban reason found
// because the user doesn't exist.
Ok(None)
}
}
}
pub async fn verify_password(
// Use clearer argument names
username: &str,