fix(rooms): harden chat-room parsing and TUI state from review findings
Adversarial review of the chat-rooms feature surfaced seven confirmed issues; all fixed with regression tests: lib (DoS hardening — a malicious/MITM server could send a tiny frame with a ~4-billion element count): - room_list: bound the name/count vector loops by remaining payload. - join_room: bound the member-list loop the same way. TUI (soulseek-rs/src/models/rooms.rs, ui): - a message for a room we already left no longer resurrects its tab (route via open_index, not ensure_open). - closing a tab now clears the unread badge on the room we land on. - a room-list refresh keeps the highlight on the same room across a re-sort (track selection by name, not index). - Esc in the room list clears a lingering filter before closing, matching the title's 'Esc: clear' hint. - chat log renders one row per line so the newest message is never clipped by wrapping.
This commit is contained in:
@@ -19,6 +19,11 @@ impl MessageHandler<ServerMessage> for JoinRoomHandler {
|
||||
let user_count = message.read_int32();
|
||||
let mut users = Vec::new();
|
||||
for _ in 0..user_count {
|
||||
// Guard against a hostile user_count outrunning the payload; each
|
||||
// username is a length-prefixed string (>= 4 bytes).
|
||||
if message.get_pointer() + 4 > message.get_size() {
|
||||
break;
|
||||
}
|
||||
users.push(message.read_string());
|
||||
}
|
||||
let _ = sender.send(ServerMessage::RoomJoined { room, users });
|
||||
@@ -29,6 +34,26 @@ impl MessageHandler<ServerMessage> for JoinRoomHandler {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hostile_user_count_does_not_hang() {
|
||||
// room="" then user_count=u32::MAX with no usernames: must return
|
||||
// promptly instead of looping ~4 billion times.
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut message = Message::new();
|
||||
message.write_raw_bytes(vec![0u8; 8]);
|
||||
message.write_string("");
|
||||
message.write_int32(u32::MAX);
|
||||
message.set_pointer(8);
|
||||
|
||||
JoinRoomHandler.handle(&mut message, tx);
|
||||
match rx.try_recv() {
|
||||
Ok(ServerMessage::RoomJoined { users, .. }) => {
|
||||
assert!(users.is_empty());
|
||||
}
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forwards_room_and_member_list() {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
|
||||
Reference in New Issue
Block a user