From 463cacdf72de9b8cc291c68062e6447f3911493c Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 9 Apr 2019 11:35:16 -0700 Subject: [PATCH] Adding slur filter. - Fixes #45 --- server/Cargo.lock | 1 + server/Cargo.toml | 3 ++- server/src/lib.rs | 33 +++++++++++++++++++++----- server/src/websocket_server/server.rs | 34 ++++++++++++++++++++++++--- ui/src/components/community-form.tsx | 1 + ui/src/components/login.tsx | 2 +- ui/src/components/post-form.tsx | 2 ++ 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/server/Cargo.lock b/server/Cargo.lock index ce4e175a7..36d2a9014 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1359,6 +1359,7 @@ dependencies = [ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/server/Cargo.toml b/server/Cargo.toml index fd3d57730..93bd6acb2 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -24,4 +24,5 @@ rand = "0.6.5" strum = "0.14.0" strum_macros = "0.14.0" jsonwebtoken = "*" -regex = "1" +regex = "*" +lazy_static = "*" diff --git a/server/src/lib.rs b/server/src/lib.rs index 9cdbd33ec..814363b49 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -12,7 +12,7 @@ pub extern crate jsonwebtoken; pub extern crate bcrypt; pub extern crate regex; #[macro_use] pub extern crate strum_macros; - +#[macro_use] pub extern crate lazy_static; pub mod schema; pub mod apub; pub mod actions; @@ -89,21 +89,42 @@ pub fn naive_now() -> NaiveDateTime { } pub fn is_email_regex(test: &str) -> bool { - let re = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap(); - re.is_match(test) + EMAIL_REGEX.is_match(test) +} + +pub fn remove_slurs(test: &str) -> String { + SLUR_REGEX.replace_all(test, "*removed*").to_string() +} + +pub fn has_slurs(test: &str) -> bool { + SLUR_REGEX.is_match(test) } #[cfg(test)] mod tests { - use {Settings, is_email_regex}; + use {Settings, is_email_regex, remove_slurs, has_slurs}; #[test] fn test_api() { assert_eq!(Settings::get().api_endpoint(), "http://0.0.0.0/api/v1"); } - #[test] - fn test_email() { + #[test] fn test_email() { assert!(is_email_regex("gush@gmail.com")); assert!(!is_email_regex("nada_neutho")); } + + #[test] fn test_slur_filter() { + let test = "coons test dindu ladyboy tranny. This is a bunch of other safe text.".to_string(); + let slur_free = "No slurs here"; + assert_eq!(remove_slurs(&test), "*removed* test *removed* *removed* *removed*. This is a bunch of other safe text.".to_string()); + assert!(has_slurs(&test)); + assert!(!has_slurs(slur_free)); + } } + + +lazy_static! { + static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap(); + static ref SLUR_REGEX: Regex = Regex::new(r"(fag(g|got|tard)?|maricos?|cock\s?sucker(s|ing)?|\bnig(\b|g?(a|er)?s?)\b|dindu(s?)|mudslime?s?|kikes?|mongoloids?|towel\s*heads?|\bspi(c|k)s?\b|\bchinks?|niglets?|beaners?|\bnips?\b|\bcoons?\b|jungle\s*bunn(y|ies?)|jigg?aboo?s?|\bpakis?\b|rag\s*heads?|gooks?|cunts?|bitch(es|ing|y)?|puss(y|ies?)|twats?|feminazis?|whor(es?|ing)|\bslut(s|t?y)?|\btrann?(y|ies?)|ladyboy(s?))").unwrap(); +} + diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs index 92542d0a7..a946c9e07 100644 --- a/server/src/websocket_server/server.rs +++ b/server/src/websocket_server/server.rs @@ -10,7 +10,7 @@ use serde_json::{Value}; use bcrypt::{verify}; use std::str::FromStr; -use {Crud, Joinable, Likeable, Followable, establish_connection, naive_now, SortType}; +use {Crud, Joinable, Likeable, Followable, establish_connection, naive_now, SortType, has_slurs, remove_slurs}; use actions::community::*; use actions::user::*; use actions::post::*; @@ -541,6 +541,10 @@ impl Perform for Register { return self.error("Passwords do not match."); } + if has_slurs(&self.username) { + return self.error("No slurs"); + } + // Register the new user let user_form = UserForm { name: self.username.to_owned(), @@ -587,6 +591,12 @@ impl Perform for CreateCommunity { } }; + if has_slurs(&self.name) || + has_slurs(&self.title) || + (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) { + return self.error("No slurs"); + } + let user_id = claims.id; // When you create a community, make sure the user becomes a moderator and a follower @@ -716,6 +726,11 @@ impl Perform for CreatePost { } }; + if has_slurs(&self.name) || + (self.body.is_some() && has_slurs(&self.body.to_owned().unwrap())) { + return self.error("No slurs"); + } + let user_id = claims.id; let post_form = PostForm { @@ -894,8 +909,10 @@ impl Perform for CreateComment { let user_id = claims.id; + let content_slurs_removed = remove_slurs(&self.content.to_owned()); + let comment_form = CommentForm { - content: self.content.to_owned(), + content: content_slurs_removed, parent_id: self.parent_id.to_owned(), post_id: self.post_id, creator_id: user_id, @@ -976,8 +993,10 @@ impl Perform for EditComment { return self.error("Incorrect creator."); } + let content_slurs_removed = remove_slurs(&self.content.to_owned()); + let comment_form = CommentForm { - content: self.content.to_owned(), + content: content_slurs_removed, parent_id: self.parent_id, post_id: self.post_id, creator_id: user_id, @@ -1197,6 +1216,11 @@ impl Perform for EditPost { fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { + if has_slurs(&self.name) || + (self.body.is_some() && has_slurs(&self.body.to_owned().unwrap())) { + return self.error("No slurs"); + } + let conn = establish_connection(); let claims = match Claims::decode(&self.auth) { @@ -1264,6 +1288,10 @@ impl Perform for EditCommunity { fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { + if has_slurs(&self.name) || has_slurs(&self.title) { + return self.error("No slurs"); + } + let conn = establish_connection(); let claims = match Claims::decode(&self.auth) { diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index b5b222c64..056c29dca 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -155,6 +155,7 @@ export class CommunityForm extends Component {
- +
diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 9845a1b1a..03ace3802 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -151,7 +151,9 @@ export class PostForm extends Component { parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { + alert(msg.error); this.state.loading = false; + this.setState(this.state); return; } else if (op == UserOperation.ListCommunities) { let res: ListCommunitiesResponse = msg;