--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/Cargo.toml Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "chat_sanitizer"
+version = "0.1.0"
+authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
+edition = "2018"
+
+[dependencies]
+unicode_skeleton = "0.1"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/bad_words.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,54 @@
+use crate::{normalized_message, MessageChecker, Severity};
+
+use std::marker::PhantomData;
+
+struct BadWordsChecker<T> {
+ blacklist: Vec<String>,
+ whitelist: Vec<String>,
+ player_id_type: PhantomData<T>,
+}
+
+impl<T> BadWordsChecker<T> {
+ pub fn new(blacklist: &[&str], whitelist: &[&str]) -> Self {
+ Self {
+ blacklist: blacklist.iter().map(|s| normalized_message(*s)).collect(),
+ whitelist: whitelist.iter().map(|s| normalized_message(*s)).collect(),
+ player_id_type: PhantomData,
+ }
+ }
+}
+
+impl<T> MessageChecker<T> for BadWordsChecker<T> {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ let msg = normalized_message(message);
+
+ // silly implementation, allows bad messages with a single good word
+ for badword in &self.blacklist {
+ if msg.contains(badword) {
+ if !self.whitelist.iter().any(|goodword| msg.contains(goodword)) {
+ return Severity::Warn;
+ }
+ }
+ }
+
+ Severity::Pass
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ fn it_works() {
+ let checker = BadWordsChecker::new(&["fsck", "poop"], &["fsck -y"]);
+ assert_eq!(checker.check(0, "group hug"), Severity::Pass);
+ assert_eq!(checker.check(0, "fpoopf"), Severity::Warn);
+ assert_eq!(checker.check(0, "PooP"), Severity::Warn);
+
+ // this one fails
+ //assert_eq!(checker.check(0, "poop 'fsck -y' poop"), Severity::Warn);
+
+ // ideally this one shouldn't fail
+ // assert_eq!(checker.check(0, "P00P"), Severity::Warn);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/caps_abuse.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,9 @@
+use crate::{MessageChecker, Severity};
+
+struct CapsAbuseChecker {}
+
+impl<T> MessageChecker<T> for CapsAbuseChecker {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ Severity::Pass
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/flood.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,9 @@
+use crate::{MessageChecker, Severity};
+
+struct FloodChecker {}
+
+impl<T> MessageChecker<T> for FloodChecker {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ Severity::Pass
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/letter_repeat.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,9 @@
+use crate::{MessageChecker, Severity};
+
+struct LetterRepeatChecker {}
+
+impl<T> MessageChecker<T> for LetterRepeatChecker {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ Severity::Pass
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/lib.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,25 @@
+pub mod bad_words;
+
+use unicode_skeleton::UnicodeSkeleton;
+
+#[derive(PartialEq, Debug)]
+enum Severity {
+ Pass,
+ Warn,
+ Silence,
+ Ban,
+}
+
+trait MessageChecker<T> {
+ fn check(&self, player_id: T, message: &str) -> Severity;
+ fn fix(&self, player_id: T, message: &str) -> Option<String> {
+ None
+ }
+}
+
+fn normalized_message(s: &str) -> String {
+ s.chars()
+ .flat_map(|c| c.to_lowercase())
+ .skeleton_chars()
+ .collect::<String>()
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/part_repeat.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,9 @@
+use crate::{MessageChecker, Severity};
+
+struct PartRepeatChecker {}
+
+impl<T> MessageChecker<T> for PartRepeatChecker {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ Severity::Pass
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/chat_sanitizer/src/url.rs Thu Dec 27 23:43:54 2018 +0100
@@ -0,0 +1,9 @@
+use crate::{MessageChecker, Severity};
+
+struct URLChecker {}
+
+impl<T> MessageChecker<T> for URLChecker {
+ fn check(&self, player_id: T, message: &str) -> Severity {
+ Severity::Pass
+ }
+}