# HG changeset patch # User alfadur # Date 1577475379 -10800 # Node ID f1205f33bf5b1427c9f7f26189a9be5945514e34 # Parent ede5f4ec48f317d019b9cd4aeff09cfd518df29b complete checker login handling diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/core/client.rs --- a/rust/hedgewars-server/src/core/client.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/core/client.rs Fri Dec 27 22:36:19 2019 +0300 @@ -2,16 +2,15 @@ use bitflags::*; bitflags! { - pub struct ClientFlags: u16 { + pub struct ClientFlags: u8 { const IS_ADMIN = 0b0000_0001; const IS_MASTER = 0b0000_0010; const IS_READY = 0b0000_0100; const IS_IN_GAME = 0b0000_1000; const IS_JOINED_MID_GAME = 0b0001_0000; - const IS_CHECKER = 0b0010_0000; - const IS_CONTRIBUTOR = 0b0100_0000; - const HAS_SUPER_POWER = 0b1000_0000; - const IS_REGISTERED = 0b0001_0000_0000; + const IS_CONTRIBUTOR = 0b0010_0000; + const HAS_SUPER_POWER = 0b0100_0000; + const IS_REGISTERED = 0b1000_0000; const NONE = 0b0000_0000; const DEFAULT = Self::NONE.bits; @@ -66,9 +65,6 @@ pub fn is_joined_mid_game(&self) -> bool { self.contains(ClientFlags::IS_JOINED_MID_GAME) } - pub fn is_checker(&self) -> bool { - self.contains(ClientFlags::IS_CHECKER) - } pub fn is_contributor(&self) -> bool { self.contains(ClientFlags::IS_CONTRIBUTOR) } @@ -94,9 +90,6 @@ pub fn set_is_joined_mid_game(&mut self, value: bool) { self.set(ClientFlags::IS_JOINED_MID_GAME, value) } - pub fn set_is_checker(&mut self, value: bool) { - self.set(ClientFlags::IS_CHECKER, value) - } pub fn set_is_contributor(&mut self, value: bool) { self.set(ClientFlags::IS_CONTRIBUTOR, value) } diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/core/server.rs --- a/rust/hedgewars-server/src/core/server.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/core/server.rs Fri Dec 27 22:36:19 2019 +0300 @@ -157,9 +157,24 @@ } } +struct HwChecker { + pub id: ClientId, + pub is_ready: bool, +} + +impl HwChecker { + pub fn new(id: ClientId) -> Self { + Self { + id, + is_ready: false, + } + } +} + pub struct HwServer { clients: IndexSlab, rooms: Slab, + checkers: IndexSlab, latest_protocol: u16, flags: ServerFlags, greetings: ServerGreetings, @@ -169,9 +184,11 @@ pub fn new(clients_limit: usize, rooms_limit: usize) -> Self { let rooms = Slab::with_capacity(rooms_limit); let clients = IndexSlab::with_capacity(clients_limit); + let checkers = IndexSlab::new(); Self { clients, rooms, + checkers, greetings: ServerGreetings::new(), latest_protocol: 58, flags: ServerFlags::empty(), @@ -242,9 +259,10 @@ } pub fn add_client(&mut self, client_id: ClientId, data: HwAnteroomClient) { - if let (Some(protocol), Some(nick)) = (data.protocol_number, data.nick) { + if data.is_checker { + self.checkers.insert(client_id, HwChecker::new(client_id)); + } else if let (Some(protocol), Some(nick)) = (data.protocol_number, data.nick) { let mut client = HwClient::new(client_id, protocol.get(), nick); - client.set_is_checker(data.is_checker); #[cfg(not(feature = "official-server"))] client.set_is_admin(data.is_local_admin); diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/handlers.rs --- a/rust/hedgewars-server/src/handlers.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/handlers.rs Fri Dec 27 22:36:19 2019 +0300 @@ -115,6 +115,10 @@ client_salt: String, server_salt: String, }, + GetCheckerAccount { + nick: String, + password: String, + }, GetReplay { id: u32, }, @@ -133,6 +137,7 @@ pub enum IoResult { AccountRegistered(bool), Account(Option), + CheckerAccount { is_registered: bool }, Replay(Option), SaveRoom(RoomId, bool), LoadRoom(RoomId, Option), @@ -410,13 +415,17 @@ response.add(Bye(REGISTRATION_REQUIRED.to_string()).send_self()); response.remove_client(client_id); } else if is_registered { - let salt = state.anteroom.clients[client_id].server_salt.clone(); - response.add(AskPassword(salt).send_self()); + let client = &state.anteroom.clients[client_id]; + response.add(AskPassword(client.server_salt.clone()).send_self()); } else if let Some(client) = state.anteroom.remove_client(client_id) { state.server.add_client(client_id, client); common::get_lobby_join_data(&state.server, response); } } + IoResult::Account(None) => { + response.add(Bye(AUTHENTICATION_FAILED.to_string()).send_self()); + response.remove_client(client_id); + } IoResult::Account(Some(info)) => { response.add(ServerAuth(format!("{:x}", info.server_hash)).send_self()); if let Some(mut client) = state.anteroom.remove_client(client_id) { @@ -427,9 +436,16 @@ common::get_lobby_join_data(&state.server, response); } } - IoResult::Account(None) => { - response.error(AUTHENTICATION_FAILED); - response.remove_client(client_id); + IoResult::CheckerAccount { is_registered } => { + if is_registered { + if let Some(client) = state.anteroom.remove_client(client_id) { + state.server.add_client(client_id, client); + response.add(LogonPassed.send_self()); + } + } else { + response.add(Bye(NO_CHECKER_RIGHTS.to_string()).send_self()); + response.remove_client(client_id); + } } IoResult::Replay(Some(replay)) => { let client = state.server.client(client_id); diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/handlers/inanteroom.rs --- a/rust/hedgewars-server/src/handlers/inanteroom.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/handlers/inanteroom.rs Fri Dec 27 22:36:19 2019 +0300 @@ -1,5 +1,6 @@ use mio; +use super::strings::*; use crate::{ core::{ anteroom::{HwAnteroom, HwAnteroomClient}, @@ -33,18 +34,12 @@ where I: Iterator, { - let has_nick_clash = - other_clients.any(|c| !c.is_checker() && c.nick == *client.nick.as_ref().unwrap()); + let has_nick_clash = other_clients.any(|c| c.nick == *client.nick.as_ref().unwrap()); if has_nick_clash { - if client.protocol_number.unwrap().get() < 38 { - response.add(Bye("User quit: Nickname is already in use".to_string()).send_self()); - LoginResult::Exit - } else { - client.nick = None; - response.add(Notice("NickAlreadyInUse".to_string()).send_self()); - LoginResult::Unchanged - } + client.nick = None; + response.add(Notice("NickAlreadyInUse".to_string()).send_self()); + LoginResult::Unchanged } else { #[cfg(feature = "official-server")] { @@ -76,10 +71,10 @@ let client = &mut server_state.anteroom.clients[client_id]; if client.nick.is_some() { - response.add(Error("Nickname already provided.".to_string()).send_self()); + response.error(NICKNAME_PROVIDED); LoginResult::Unchanged } else if is_name_illegal(&nick) { - response.add(Bye("Illegal nickname! Nicknames must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string()).send_self()); + response.add(Bye(ILLEGAL_CLIENT_NAME.to_string()).send_self()); LoginResult::Exit } else { client.nick = Some(nick.clone()); @@ -95,11 +90,11 @@ HwProtocolMessage::Proto(proto) => { let client = &mut server_state.anteroom.clients[client_id]; if client.protocol_number.is_some() { - response.add(Error("Protocol already known.".to_string()).send_self()); + response.error(PROTOCOL_PROVIDED); LoginResult::Unchanged - } else if proto == 0 { - response.add(Error("Bad number.".to_string()).send_self()); - LoginResult::Unchanged + } else if proto < 48 { + response.add(Bye(PROTOCOL_TOO_OLD.to_string()).send_self()); + LoginResult::Exit } else { client.protocol_number = NonZeroU16::new(proto); response.add(Proto(proto).send_self()); @@ -131,17 +126,29 @@ HwProtocolMessage::Checker(protocol, nick, password) => { let client = &mut server_state.anteroom.clients[client_id]; if protocol == 0 { - response.add(Error("Bad number.".to_string()).send_self()); + response.error("Bad number."); LoginResult::Unchanged } else { client.protocol_number = NonZeroU16::new(protocol); - client.nick = Some(nick); client.is_checker = true; - LoginResult::Complete + #[cfg(not(feature = "official-server"))] + { + response.request_io(super::IoTask::GetCheckerAccount { + nick: nick, + password: password, + }); + LoginResult::Unchanged + } + + #[cfg(feature = "official-server")] + { + response.add(LogonPassed.send_self()); + LoginResult::Complete + } } } _ => { - warn!("Incorrect command in logging-in state"); + warn!("Incorrect command in anteroom"); LoginResult::Unchanged } } diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/handlers/strings.rs --- a/rust/hedgewars-server/src/handlers/strings.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/handlers/strings.rs Fri Dec 27 22:36:19 2019 +0300 @@ -1,11 +1,17 @@ pub const ACCESS_DENIED: &str = "Access denied."; -pub const AUTHENTICATION_FAILED: &str = "Authentication failed."; +pub const AUTHENTICATION_FAILED: &str = "Authentication failed"; +pub const BAD_NUMBER: &str = "Bad number."; +pub const ILLEGAL_CLIENT_NAME: &str = "Illegal nickname! Nicknames must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}"; pub const ILLEGAL_ROOM_NAME: &str = "Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}"; +pub const NICKNAME_PROVIDED: &str = "Nickname already provided."; +pub const NO_CHECKER_RIGHTS: &str = "No checker rights"; pub const NO_ROOM: &str = "No such room."; pub const NO_TEAM: &str = "No such team."; pub const NO_TEAM_TO_REMOVE: &str = "Error: The team you tried to remove does not exist."; pub const NO_USER: &str = "No such user."; pub const NOT_MASTER: &str = "You're not the room master!"; +pub const PROTOCOL_PROVIDED: &str = "Protocol already known."; +pub const PROTOCOL_TOO_OLD: &str = "Protocol version is too old"; pub const REPLAY_LOAD_FAILED: &str = "Could't load the replay"; pub const REPLAY_NOT_SUPPORTED: &str = "This server does not support replays!"; pub const REGISTRATION_REQUIRED: &str = "This server only allows registered users to join."; diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/protocol/messages.rs --- a/rust/hedgewars-server/src/protocol/messages.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/protocol/messages.rs Fri Dec 27 22:36:19 2019 +0300 @@ -120,6 +120,7 @@ Proto(u16), AskPassword(String), ServerAuth(String), + LogonPassed, LobbyLeft(String, String), LobbyJoined(Vec), @@ -390,6 +391,7 @@ Proto(proto) => msg!["PROTO", proto], AskPassword(salt) => msg!["ASKPASSWORD", salt], ServerAuth(hash) => msg!["SERVER_AUTH", hash], + LogonPassed => msg!["LOGONPASSED"], LobbyLeft(nick, msg) => msg!["LOBBY:LEFT", nick, msg], LobbyJoined(nicks) => construct_message(&["LOBBY:JOINED"], &nicks), ClientFlags(flags, nicks) => construct_message(&["CLIENT_FLAGS", flags], &nicks), diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/server/database.rs --- a/rust/hedgewars-server/src/server/database.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/server/database.rs Fri Dec 27 22:36:19 2019 +0300 @@ -86,6 +86,23 @@ } } + pub fn get_checker_account( + &mut self, + nick: &str, + checker_password: &str, + ) -> Result { + if let Some(pool) = &self.pool { + if let Some(row) = pool.first_exec(GET_ACCOUNT_QUERY, params! { "username" => nick })? { + let (mut password, _, _) = from_row_opt::<(String, i32, i32)>(row)?; + Ok(checker_password == password) + } else { + Ok(false) + } + } else { + Err(DriverError::SetupError.into()) + } + } + pub fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> { if let Some(pool) = &self.pool { for mut stmt in pool.prepare(STORE_STATS_QUERY).into_iter() { diff -r ede5f4ec48f3 -r f1205f33bf5b rust/hedgewars-server/src/server/io.rs --- a/rust/hedgewars-server/src/server/io.rs Thu Dec 26 21:55:51 2019 +0300 +++ b/rust/hedgewars-server/src/server/io.rs Fri Dec 27 22:36:19 2019 +0300 @@ -61,6 +61,18 @@ } } + IoTask::GetCheckerAccount { nick, password } => { + match db.get_checker_account(&nick, &password) { + Ok(is_registered) => IoResult::CheckerAccount { is_registered }, + Err(e) => { + warn!("Unable to get checker account data: {}", e); + IoResult::CheckerAccount { + is_registered: false, + } + } + } + } + IoTask::GetReplay { id } => { let result = match db.get_replay_name(id) { Ok(Some(filename)) => {