From 5e8fe5a753527b77832817e50bd815dc7d69009b Mon Sep 17 00:00:00 2001 From: Zoey Date: Tue, 23 Apr 2024 21:45:49 -0700 Subject: [PATCH] add /ban, /allowentry, and /setpass commands, resolving #4 --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + src/command.rs | 69 ++++++++++++++++++++++++++++++++++--- src/server/network.rs | 79 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 149 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20fceb4..c866dcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,7 @@ dependencies = [ "flate2", "half", "internment", + "nanoid", "optional_struct", "parking_lot", "rand", @@ -243,6 +244,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand", +] + [[package]] name = "num_cpus" version = "1.16.0" diff --git a/Cargo.toml b/Cargo.toml index 890195a..5a1e361 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ bytes = "1" flate2 = "1" half = "2" internment = {version = "0.8", features = ["serde"]} +nanoid = "0.4" optional_struct = "0.4" parking_lot = "0.12" rand = "0.8" diff --git a/src/command.rs b/src/command.rs index bb3e95e..77547d3 100644 --- a/src/command.rs +++ b/src/command.rs @@ -2,13 +2,26 @@ use crate::player::PlayerType; const CMD_ME: &str = "me"; const CMD_SAY: &str = "say"; -const CMD_SET_PERM: &str = "setperm"; +const CMD_SETPERM: &str = "setperm"; const CMD_KICK: &str = "kick"; const CMD_STOP: &str = "stop"; const CMD_HELP: &str = "help"; +const CMD_BAN: &str = "ban"; +const CMD_ALLOWENTRY: &str = "allowentry"; +const CMD_SETPASS: &str = "setpass"; /// list of commands available on the server -pub const COMMANDS_LIST: &[&str] = &[CMD_ME, CMD_SAY, CMD_SET_PERM, CMD_KICK, CMD_STOP, CMD_HELP]; +pub const COMMANDS_LIST: &[&str] = &[ + CMD_ME, + CMD_SAY, + CMD_SETPERM, + CMD_KICK, + CMD_STOP, + CMD_HELP, + CMD_BAN, + CMD_ALLOWENTRY, + CMD_SETPASS, +]; /// enum for possible commands #[derive(Debug, Clone)] @@ -33,6 +46,18 @@ pub enum Command<'m> { Stop, /// gets help about the given command, or about all commands if no command is given Help { command: Option<&'m str> }, + /// bans a player from the server + Ban { + player_username: &'m str, + message: Option<&'m str>, + }, + /// allows a player entry into the server + AllowEntry { + player_username: &'m str, + password: Option<&'m str>, + }, + /// sets the current player's password + SetPass { password: &'m str }, } impl<'m> Command<'m> { @@ -45,7 +70,7 @@ impl<'m> Command<'m> { Ok(match command_name { CMD_ME => Self::Me { action: arguments }, CMD_SAY => Self::Say { message: arguments }, - CMD_SET_PERM => Self::SetPermissions { + CMD_SETPERM => Self::SetPermissions { player_username: Self::next_string(&mut arguments)?, permissions: arguments.trim().try_into()?, }, @@ -59,6 +84,27 @@ impl<'m> Command<'m> { CMD_HELP => Self::Help { command: (!arguments.is_empty()).then_some(arguments), }, + CMD_BAN => { + let player_username = Self::next_string(&mut arguments)?; + let message = arguments.trim(); + let message = (!message.is_empty()).then_some(message); + Self::Ban { + player_username, + message, + } + } + CMD_ALLOWENTRY => { + let player_username = Self::next_string(&mut arguments)?; + let password = arguments.trim(); + let password = (!password.is_empty()).then_some(password); + Self::AllowEntry { + player_username, + password, + } + } + CMD_SETPASS => Self::SetPass { + password: arguments.trim(), + }, _ => return Err(format!("Unknown command: {command_name}")), }) } @@ -68,10 +114,13 @@ impl<'m> Command<'m> { match self { Self::Me { .. } => CMD_ME, Self::Say { .. } => CMD_SAY, - Self::SetPermissions { .. } => CMD_SET_PERM, + Self::SetPermissions { .. } => CMD_SETPERM, Self::Kick { .. } => CMD_KICK, Self::Stop => CMD_STOP, Self::Help { .. } => CMD_HELP, + Self::Ban { .. } => CMD_BAN, + Self::AllowEntry { .. } => CMD_ALLOWENTRY, + Self::SetPass { .. } => CMD_SETPASS, } } @@ -86,6 +135,7 @@ impl<'m> Command<'m> { CMD_ME => PlayerType::Normal, CMD_STOP => PlayerType::Operator, CMD_HELP => PlayerType::Normal, + CMD_SETPASS => PlayerType::Normal, _ => PlayerType::Moderator, } } @@ -103,7 +153,7 @@ impl<'m> Command<'m> { c(""), "&fSends a message as being from the server.".to_string(), ], - CMD_SET_PERM => vec![ + CMD_SETPERM => vec![ c(" "), "&fSets a player's permission level.".to_string(), ], @@ -119,6 +169,15 @@ impl<'m> Command<'m> { c("[command]"), "&fGets a list of commands or help about a command.".to_string(), ], + CMD_BAN => vec![ + c(" [reason]"), + "&fBans a player from the server.".to_string(), + ], + CMD_ALLOWENTRY => vec![ + c(""), + "&fAllows a player into the server.".to_string(), + ], + CMD_SETPASS => vec![c(""), "&fUpdates your password.".to_string()], _ => vec!["&eUnknown command!".to_string()], } } diff --git a/src/server/network.rs b/src/server/network.rs index 0249557..c911b13 100644 --- a/src/server/network.rs +++ b/src/server/network.rs @@ -455,11 +455,12 @@ async fn handle_stream_inner( continue; } - other_player.should_be_kicked = Some( - message - .unwrap_or("") - .to_string(), - ); + other_player.should_be_kicked = + Some(format!( + "Kicked: {}", + message + .unwrap_or("") + )); msg!(format!( "{} has been kicked", other_player.username @@ -517,6 +518,74 @@ async fn handle_stream_inner( msg!(msg); } } + + Command::Ban { + player_username, + message, + } => { + let player_perms = player.permissions; + if let ServerProtectionMode::PasswordsByUser(passwords) = &mut data.config.protection_mode { + if !passwords.contains_key(player_username) { + msg!("&cPlayer is already banned!".to_string()); + } else { + passwords.remove(player_username); + data.config.player_perms.remove(player_username); + data.config_needs_saving = true; + if let Some(other_player) = + data.players.iter_mut().find(|p| { + p.username == player_username + }) { + if player_perms + <= other_player.permissions + { + msg!("&cThis player outranks or is the same rank as you".to_string()); + continue; + } + + other_player.should_be_kicked = + Some(format!("Banned: {}", message.unwrap_or(""))); + } + msg!(format!( + "{} has been banned", + player_username + )); + } + } else { + msg!("&cServer must be set to per-user passwords!".to_string()); + } + } + + Command::AllowEntry { + player_username, + password, + } => { + if let ServerProtectionMode::PasswordsByUser(passwords) = &mut data.config.protection_mode { + if passwords.contains_key(player_username) { + msg!("&cPlayer is already allowed in the server!".to_string()); + } else { + let password = password.map(|p| p.to_string()).unwrap_or_else(|| { + nanoid::nanoid!() + }); + msg!(format!("{player_username} is now allowed in the server.")); + msg!(format!("Password: {password}")); + passwords.insert(player_username.to_string(), password); + data.config_needs_saving = true; + } + } else { + msg!("&cServer must be set to per-user passwords!".to_string()); + } + } + + Command::SetPass { password } => { + let username = player.username.clone(); + if let ServerProtectionMode::PasswordsByUser(passwords) = &mut data.config.protection_mode { + passwords.insert(username, password.to_string()); + data.config_needs_saving = true; + msg!("Updated password!".to_string()); + } else { + msg!("&cServer must be set to per-user passwords!".to_string()); + } + } } } Err(msg) => {