Move the pass and name checks to its own module outside the Game struct.

This way it can be called from methods that are not members of Game
such as the password set command. It does require some global variables
and an initializion to get setup from the configuration.
master
rasul 5 years ago
parent 73fbc8750d
commit bdf8f86ba5

@ -0,0 +1,90 @@
use std::cell::RefCell;
use crate::config::Player;
// this global stuff is so that we can load up the config and check stuff without
// being part of the Game struct
thread_local! {
pub static NAME_MIN: RefCell<usize> = RefCell::new(0);
pub static NAME_MAX: RefCell<usize> = RefCell::new(0);
pub static NAME_CHARS: RefCell<&'static str> = RefCell::new("");
pub static PASS_MIN: RefCell<usize> = RefCell::new(0);
pub static PASS_MAX: RefCell<usize> = RefCell::new(0);
pub static PASS_CHARS: RefCell<&'static str> = RefCell::new("");
}
/// Return value for check functions
#[derive(Debug)]
pub enum PlayerCheck {
/// The value checks out
Ok(String),
/// There is one or more issues
Err(Vec<String>),
}
pub fn init(config: &Player) {
NAME_MIN.with(|n| *n.borrow_mut() = config.name_min);
NAME_MAX.with(|n| *n.borrow_mut() = config.name_max);
NAME_CHARS.with(|n| *n.borrow_mut() = Box::leak(config.name_chars.clone().into_boxed_str()));
PASS_MIN.with(|p| *p.borrow_mut() = config.pass_min);
PASS_MAX.with(|p| *p.borrow_mut() = config.pass_max);
PASS_CHARS.with(|p| *p.borrow_mut() = Box::leak(config.pass_chars.clone().into_boxed_str()));
}
/// Check the player name to ensure it meets guidelines
pub fn player_name<S: Into<String>>(name: S) -> PlayerCheck {
let name = name.into();
let name = name.trim();
let mut err_vec = Vec::<String>::new();
if name.len() < NAME_MIN.with(|n| *n.borrow()) {
err_vec.push(format!("{} character minimum", NAME_MIN.with(|n| *n.borrow())));
} else if name.len() > NAME_MAX.with(|n| *n.borrow()) {
err_vec.push(format!("{} character maximum", NAME_MAX.with(|n| *n.borrow())));
}
for c in name.chars() {
if !NAME_CHARS.with(|n| *n.borrow()).contains(&c.to_string()) {
err_vec.push(format!(
"Allowed characters are: {}",
NAME_CHARS.with(|n| *n.borrow())
));
break;
}
}
if !err_vec.is_empty() {
PlayerCheck::Err(err_vec)
} else {
PlayerCheck::Ok(name.into())
}
}
/// Check the password to ensure it meets password requirements
pub fn player_password<S: Into<String>>(password: S) -> PlayerCheck {
let password = password.into();
let mut err_vec = Vec::<String>::new();
if password.len() < PASS_MIN.with(|p| *p.borrow()) {
err_vec.push(format!("{} character minimum", PASS_MIN.with(|p| *p.borrow())));
} else if password.len() > PASS_MAX.with(|p| *p.borrow()) {
err_vec.push(format!("{} character maximum", PASS_MAX.with(|p| *p.borrow())));
}
for c in password.chars() {
if !PASS_CHARS.with(|p| *p.borrow()).contains(&c.to_string()) {
err_vec.push(format!(
"Allowed characters are: {}",
PASS_CHARS.with(|p| *p.borrow())
));
break;
}
}
if err_vec.is_empty() {
PlayerCheck::Ok(password.into())
} else {
PlayerCheck::Err(err_vec)
}
}

@ -1,70 +0,0 @@
use crate::game::Game;
/// Return value for check functions
#[derive(Debug)]
pub enum PlayerCheck {
/// The value checks out
Ok(String),
/// There is one or more issues
Err(Vec<String>),
}
impl Game {
/// Check the player name to ensure it meets guidelines
pub fn check_player_name<S: Into<String>>(&self, name: S) -> PlayerCheck {
let name = name.into();
let name = name.trim();
let mut err_vec = Vec::<String>::new();
if name.len() < self.config.player.name_min {
err_vec.push(format!("{} character minimum", self.config.player.name_min));
} else if name.len() > self.config.player.name_max {
err_vec.push(format!("{} character maximum", self.config.player.name_max));
}
for c in name.chars() {
if !self.config.player.name_chars.contains(&c.to_string()) {
err_vec.push(format!(
"Allowed characters are: {}",
self.config.player.name_chars
));
break;
}
}
if !err_vec.is_empty() {
PlayerCheck::Err(err_vec)
} else {
PlayerCheck::Ok(name.into())
}
}
/// Check the password to ensure it meets password requirements
pub fn check_player_password<S: Into<String>>(&self, password: S) -> PlayerCheck {
let password = password.into();
let mut err_vec = Vec::<String>::new();
if password.len() < self.config.player.pass_min {
err_vec.push(format!("{} character minimum", self.config.player.pass_min));
} else if password.len() > self.config.player.pass_max {
err_vec.push(format!("{} character maximum", self.config.player.pass_max));
}
for c in password.chars() {
if !self.config.player.pass_chars.contains(&c.to_string()) {
err_vec.push(format!(
"Allowed characters are: {}",
self.config.player.pass_chars
));
break;
}
}
if err_vec.is_empty() {
PlayerCheck::Ok(password.into())
} else {
PlayerCheck::Err(err_vec)
}
}
}

@ -1,4 +1,3 @@
mod check_player;
#[allow(clippy::module_inception)]
mod game;
mod handle_events;
@ -7,5 +6,5 @@ mod new;
mod process_recv_message;
mod state;
pub use check_player::*;
//pub use check_player::*;
pub use game::Game;

@ -3,6 +3,7 @@ use std::collections::{HashMap, VecDeque};
use log::{debug, info};
use mio::{Events, Interest, Poll, Token};
use crate::check;
use crate::client::Client;
use crate::config::Config;
use crate::database::Db;
@ -21,6 +22,9 @@ impl Game {
try_print(logger::init(log_level), "Unable to initialize logger")?;
debug!("Initialized logging facility");
debug!("Setting up check config");
check::init(&config.player);
debug!("Opening database");
let db = Db::open(&config.database)?;

@ -1,8 +1,9 @@
use chrono::Utc;
use mio::Token;
use crate::check;
use crate::command::Command;
use crate::game::{Game, PlayerCheck};
use crate::game::Game;
use crate::log_error;
use crate::password::Password;
use crate::player::Player;
@ -19,8 +20,8 @@ impl Game {
if message.is_empty() {
send_queue.push(token, "\n\nUsername: ", false, None);
} else {
match self.check_player_name(message) {
PlayerCheck::Ok(name) => match self.db.find_player_by_name(&name) {
match check::player_name(message) {
check::PlayerCheck::Ok(name) => match self.db.find_player_by_name(&name) {
Ok(Some(_)) => {
send_queue.push(
token,
@ -41,7 +42,7 @@ impl Game {
send_queue.push(token, "\nError\n\nUsername: ", false, None);
}
},
PlayerCheck::Err(err) => {
check::PlayerCheck::Err(err) => {
send_queue.push(token, "\nInvalid username:\n", false, None);
for line in err {
send_queue.push(token, format!("{}\n", line), false, None);
@ -81,8 +82,8 @@ impl Game {
Some(State::Login(Login::Username)),
);
} else {
match self.check_player_password(message) {
PlayerCheck::Ok(pass) => {
match check::player_password(message) {
check::PlayerCheck::Ok(pass) => {
match Password::new(pass) {
Ok(password) => send_queue.push(
token,
@ -105,7 +106,7 @@ impl Game {
},
};
}
PlayerCheck::Err(err) => {
check::PlayerCheck::Err(err) => {
send_queue.push(token, "\nInvalid password:\n", false, None);
for line in err {
send_queue.push(token, format!("{}\n", line), false, None);

@ -1,5 +1,6 @@
//! The Rude Mud
pub mod check;
pub mod client;
pub mod command;
pub mod config;

@ -1,3 +1,4 @@
mod check;
mod client;
mod command;
mod config;

Loading…
Cancel
Save