Enhance room access validation and debugging in command handling
Improved error handling in `handle_init_command` and `handle_join_command` to provide clearer feedback when room resolution fails. Added detailed debug logging for room access attempts, including client ID and requested room information, when debugging is enabled. Introduced a new function, `room_debug_enabled`, to toggle debug logging based on environment variables. Updated password validation logic to require a password when one is set for a room.
This commit is contained in:
@@ -2,6 +2,7 @@ use crate::types::{ChatState, ClientId, Command, RoomMeta, ServerConfig};
|
|||||||
use bcrypt::verify as bcrypt_verify;
|
use bcrypt::verify as bcrypt_verify;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::env;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
@@ -160,11 +161,22 @@ async fn handle_init_command(
|
|||||||
let (resolved_room_name, room_meta) = {
|
let (resolved_room_name, room_meta) = {
|
||||||
let guard = state.read().await;
|
let guard = state.read().await;
|
||||||
let Some(resolved_room_name) = resolve_room_name(&guard, &room_name) else {
|
let Some(resolved_room_name) = resolve_room_name(&guard, &room_name) else {
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
let known_rooms = guard.room_meta.keys().cloned().collect::<Vec<_>>();
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][init] client_id={client_id} requested_room='{room_name}' resolve_failed known_rooms={known_rooms:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(room_meta) = guard.room_meta.get(&resolved_room_name).cloned() else {
|
let Some(room_meta) = guard.room_meta.get(&resolved_room_name).cloned() else {
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][init] client_id={client_id} requested_room='{room_name}' resolved_room='{resolved_room_name}' missing_meta"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
(resolved_room_name, room_meta)
|
(resolved_room_name, room_meta)
|
||||||
@@ -181,6 +193,20 @@ async fn handle_init_command(
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][init] client_id={client_id} user='{}' room='{}' denied='{}' user_profile={{fid:{:?},gender:{:?},age:{:?},rights:{:?},right_ids:{:?}}} room_meta={:?}",
|
||||||
|
profile.display_name,
|
||||||
|
resolved_room_name,
|
||||||
|
access_error,
|
||||||
|
profile.falukant_user_id,
|
||||||
|
profile.gender_id,
|
||||||
|
profile.age,
|
||||||
|
profile.rights,
|
||||||
|
profile.right_type_ids,
|
||||||
|
room_meta
|
||||||
|
);
|
||||||
|
}
|
||||||
send_error(client_id, Arc::clone(&state), access_error).await;
|
send_error(client_id, Arc::clone(&state), access_error).await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -199,7 +225,12 @@ async fn handle_init_command(
|
|||||||
}
|
}
|
||||||
if !guard.room_meta.contains_key(&resolved_room_name) {
|
if !guard.room_meta.contains_key(&resolved_room_name) {
|
||||||
drop(guard);
|
drop(guard);
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][init] client_id={client_id} resolved_room='{resolved_room_name}' vanished_before_join"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,11 +330,22 @@ async fn handle_join_command(
|
|||||||
let (resolved_room, room_meta, falukant_user_id, gender_id, age, right_type_ids, rights) = {
|
let (resolved_room, room_meta, falukant_user_id, gender_id, age, right_type_ids, rights) = {
|
||||||
let guard = state.read().await;
|
let guard = state.read().await;
|
||||||
let Some(resolved_room) = resolve_room_name(&guard, &room) else {
|
let Some(resolved_room) = resolve_room_name(&guard, &room) else {
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
let known_rooms = guard.room_meta.keys().cloned().collect::<Vec<_>>();
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][join] client_id={client_id} requested_room='{room}' resolve_failed known_rooms={known_rooms:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(room_meta) = guard.room_meta.get(&resolved_room).cloned() else {
|
let Some(room_meta) = guard.room_meta.get(&resolved_room).cloned() else {
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][join] client_id={client_id} requested_room='{room}' resolved_room='{resolved_room}' missing_meta"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(client) = guard.clients.get(&client_id) else {
|
let Some(client) = guard.clients.get(&client_id) else {
|
||||||
@@ -331,6 +373,19 @@ async fn handle_join_command(
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][join] client_id={client_id} room='{}' denied='{}' user={{fid:{:?},gender:{:?},age:{:?},rights:{:?},right_ids:{:?}}} room_meta={:?}",
|
||||||
|
resolved_room,
|
||||||
|
access_error,
|
||||||
|
falukant_user_id,
|
||||||
|
gender_id,
|
||||||
|
age,
|
||||||
|
rights,
|
||||||
|
right_type_ids,
|
||||||
|
room_meta
|
||||||
|
);
|
||||||
|
}
|
||||||
send_error(client_id, Arc::clone(&state), access_error).await;
|
send_error(client_id, Arc::clone(&state), access_error).await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -338,7 +393,12 @@ async fn handle_join_command(
|
|||||||
let mut guard = state.write().await;
|
let mut guard = state.write().await;
|
||||||
if !guard.room_meta.contains_key(&resolved_room) {
|
if !guard.room_meta.contains_key(&resolved_room) {
|
||||||
drop(guard);
|
drop(guard);
|
||||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][join] client_id={client_id} resolved_room='{resolved_room}' vanished_before_join"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
send_error(client_id, Arc::clone(&state), "room_not_found").await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Some(client) = guard.clients.get_mut(&client_id) else {
|
let Some(client) = guard.clients.get_mut(&client_id) else {
|
||||||
@@ -883,6 +943,12 @@ async fn handle_create_room_command(
|
|||||||
empty_since_unix: Some(now_unix()),
|
empty_since_unix: Some(now_unix()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if room_debug_enabled() {
|
||||||
|
eprintln!(
|
||||||
|
"[yourchat2][room-debug][create] client_id={client_id} room='{}' owner_chat_user_id={} created",
|
||||||
|
parsed.room_name, owner_chat_user_id
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state::send_room_list(client_id, Arc::clone(&state)).await;
|
state::send_room_list(client_id, Arc::clone(&state)).await;
|
||||||
state::send_to_client(
|
state::send_to_client(
|
||||||
@@ -1133,8 +1199,13 @@ async fn room_access_allowed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(room_password) = &room.password {
|
if let Some(room_password) = &room.password {
|
||||||
if !room_password.is_empty() && !password_matches(room_password, provided_password) {
|
if !room_password.is_empty() {
|
||||||
return Err("room_password_invalid");
|
if provided_password.trim().is_empty() {
|
||||||
|
return Err("room_password_required");
|
||||||
|
}
|
||||||
|
if !password_matches(room_password, provided_password) {
|
||||||
|
return Err("room_password_invalid");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1361,6 +1432,13 @@ fn now_unix() -> i64 {
|
|||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn room_debug_enabled() -> bool {
|
||||||
|
matches!(
|
||||||
|
env::var("CHAT_DEBUG_ROOM_ACCESS").ok().as_deref(),
|
||||||
|
Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") | Some("on") | Some("ON")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn command_from_chat_line(message: &str, token: Option<String>) -> Option<Command> {
|
fn command_from_chat_line(message: &str, token: Option<String>) -> Option<Command> {
|
||||||
let trimmed = message.trim();
|
let trimmed = message.trim();
|
||||||
if !trimmed.starts_with('/') {
|
if !trimmed.starts_with('/') {
|
||||||
|
|||||||
Reference in New Issue
Block a user