Start chat_sanitizer package inspired by chat bot on pokerth server
authorunc0rr
Thu, 27 Dec 2018 23:43:54 +0100
changeset 14503 831ecafd74c6
parent 14502 abe0a561005e
child 14504 6cc0fce249f9
Start chat_sanitizer package inspired by chat bot on pokerth server
rust/chat_sanitizer/Cargo.toml
rust/chat_sanitizer/src/bad_words.rs
rust/chat_sanitizer/src/caps_abuse.rs
rust/chat_sanitizer/src/flood.rs
rust/chat_sanitizer/src/letter_repeat.rs
rust/chat_sanitizer/src/lib.rs
rust/chat_sanitizer/src/part_repeat.rs
rust/chat_sanitizer/src/url.rs
--- /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
+    }
+}