Created banned words file

By default, it's an empty list
This commit is contained in:
T-Dark0 2020-07-16 14:05:35 +00:00 committed by Marcel
parent 9195c06c95
commit d5e9e19881
4 changed files with 157 additions and 3 deletions

View File

@ -0,0 +1,115 @@
use std::fmt::{self, Display};
#[derive(Debug, Default)]
pub struct AliasValidator {
banned_substrings: Vec<String>,
}
impl AliasValidator {
pub fn new(banned_substrings: Vec<String>) -> Self {
let banned_substrings = banned_substrings
.iter()
.map(|string| string.to_lowercase())
.collect();
AliasValidator { banned_substrings }
}
pub fn validate(&self, alias: &str) -> Result<(), ValidatorError> {
let lowercase_alias = alias.to_lowercase();
for banned_word in self.banned_substrings.iter() {
if lowercase_alias.contains(banned_word) {
return Err(ValidatorError::Forbidden(
alias.to_owned(),
banned_word.to_owned(),
));
}
}
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub enum ValidatorError {
Forbidden(String, String),
}
impl Display for ValidatorError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Forbidden(name, _) => write!(
formatter,
"Character name \"{}\" contains a banned word",
name
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn multiple_matches() {
let banned_substrings = vec!["bad".to_owned(), "worse".to_owned()];
let validator = AliasValidator::new(banned_substrings);
let bad_alias = "Badplayery Mc WorsePlayeryFace";
let result = validator.validate(bad_alias);
assert_eq!(
result,
Err(ValidatorError::Forbidden(
bad_alias.to_owned(),
"bad".to_owned()
))
);
}
#[test]
fn single_lowercase_match() {
let banned_substrings = vec!["blue".to_owned()];
let validator = AliasValidator::new(banned_substrings);
let bad_alias = "blueName";
let result = validator.validate(bad_alias);
assert_eq!(
result,
Err(ValidatorError::Forbidden(
bad_alias.to_owned(),
"blue".to_owned()
))
);
}
#[test]
fn single_case_insensitive_match() {
let banned_substrings = vec!["GrEEn".to_owned()];
let validator = AliasValidator::new(banned_substrings);
let bad_alias = "gReenName";
let result = validator.validate(bad_alias);
assert_eq!(
result,
Err(ValidatorError::Forbidden(
bad_alias.to_owned(),
"green".to_owned()
))
);
}
#[test]
fn mp_matches() {
let banned_substrings = vec!["orange".to_owned()];
let validator = AliasValidator::new(banned_substrings);
let good_alias = "ReasonableName";
let result = validator.validate(good_alias);
assert_eq!(result, Ok(()));
}
}

View File

@ -2,6 +2,7 @@
#![allow(clippy::option_map_unit_fn)]
#![feature(drain_filter, option_zip)]
pub mod alias_validator;
pub mod auth_provider;
pub mod chunk_generator;
pub mod client;
@ -20,6 +21,7 @@ pub mod sys;
pub use crate::{error::Error, events::Event, input::Input, settings::ServerSettings};
use crate::{
alias_validator::AliasValidator,
auth_provider::AuthProvider,
chunk_generator::ChunkGenerator,
client::{Client, RegionSubscription},
@ -137,6 +139,30 @@ impl Server {
state.ecs_mut().register::<RegionSubscription>();
state.ecs_mut().register::<Client>();
//Alias validator
let banned_words_paths = &settings.banned_words_files;
let mut banned_words = Vec::new();
for path in banned_words_paths {
let mut list = match std::fs::File::open(&path) {
Ok(file) => match ron::de::from_reader(&file) {
Ok(vec) => vec,
Err(error) => {
tracing::warn!(?error, ?file, "Couldn't deserialize banned words file");
return Err(Error::Other(error.to_string()));
},
},
Err(error) => {
tracing::warn!(?error, ?path, "couldn't open banned words file");
return Err(Error::Other(error.to_string()));
},
};
banned_words.append(&mut list);
}
let banned_words_count = banned_words.len();
tracing::debug!(?banned_words_count);
tracing::trace!(?banned_words);
state.ecs_mut().insert(AliasValidator::new(banned_words));
#[cfg(feature = "worldgen")]
let world = World::generate(settings.world_seed, WorldOpts {
seed_elements: true,

View File

@ -25,6 +25,7 @@ pub struct ServerSettings {
pub map_file: Option<FileOpts>,
pub persistence_db_dir: String,
pub max_view_distance: Option<u32>,
pub banned_words_files: Vec<PathBuf>,
}
impl Default for ServerSettings {
@ -63,6 +64,7 @@ impl Default for ServerSettings {
whitelist: Vec::new(),
persistence_db_dir: "saves".to_owned(),
max_view_distance: Some(30),
banned_words_files: Vec::new(),
}
}
}

View File

@ -1,7 +1,7 @@
use super::SysTimer;
use crate::{
auth_provider::AuthProvider, client::Client, persistence::character::CharacterLoader,
ServerSettings, CLIENT_TIMEOUT,
alias_validator::AliasValidator, auth_provider::AuthProvider, client::Client,
persistence::character::CharacterLoader, ServerSettings, CLIENT_TIMEOUT,
};
use common::{
comp::{
@ -55,6 +55,7 @@ impl Sys {
players: &mut WriteStorage<'_, Player>,
controllers: &mut WriteStorage<'_, Controller>,
settings: &Read<'_, ServerSettings>,
alias_validator: &ReadExpect<'_, AliasValidator>,
) -> Result<(), crate::error::Error> {
loop {
let msg = client.recv().await?;
@ -347,7 +348,14 @@ impl Sys {
}
},
ClientMsg::CreateCharacter { alias, tool, body } => {
if let Some(player) = players.get(entity) {
if let Err(error) = alias_validator.validate(&alias) {
tracing::debug!(
?error,
?alias,
"denied alias as it contained a banned word"
);
client.notify(ServerMsg::CharacterActionError(error.to_string()));
} else if let Some(player) = players.get(entity) {
character_loader.create_character(
entity,
player.uuid().to_string(),
@ -413,6 +421,7 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Client>,
WriteStorage<'a, Controller>,
Read<'a, ServerSettings>,
ReadExpect<'a, AliasValidator>,
);
#[allow(clippy::match_ref_pats)] // TODO: Pending review in #587
@ -443,6 +452,7 @@ impl<'a> System<'a> for Sys {
mut clients,
mut controllers,
settings,
alias_validator,
): Self::SystemData,
) {
timer.start();
@ -502,6 +512,7 @@ impl<'a> System<'a> for Sys {
&mut players,
&mut controllers,
&settings,
&alias_validator,
).fuse() => err,
)
});