Adding slur filter.

- Fixes #45
This commit is contained in:
Dessalines 2019-04-09 11:35:16 -07:00
parent 8aa58e479e
commit 92670d1a5e
7 changed files with 65 additions and 11 deletions

1
server/Cargo.lock generated
View file

@ -1359,6 +1359,7 @@ dependencies = [
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -24,4 +24,5 @@ rand = "0.6.5"
strum = "0.14.0" strum = "0.14.0"
strum_macros = "0.14.0" strum_macros = "0.14.0"
jsonwebtoken = "*" jsonwebtoken = "*"
regex = "1" regex = "*"
lazy_static = "*"

View file

@ -12,7 +12,7 @@ pub extern crate jsonwebtoken;
pub extern crate bcrypt; pub extern crate bcrypt;
pub extern crate regex; pub extern crate regex;
#[macro_use] pub extern crate strum_macros; #[macro_use] pub extern crate strum_macros;
#[macro_use] pub extern crate lazy_static;
pub mod schema; pub mod schema;
pub mod apub; pub mod apub;
pub mod actions; pub mod actions;
@ -89,21 +89,42 @@ pub fn naive_now() -> NaiveDateTime {
} }
pub fn is_email_regex(test: &str) -> bool { 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(); EMAIL_REGEX.is_match(test)
re.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)] #[cfg(test)]
mod tests { mod tests {
use {Settings, is_email_regex}; use {Settings, is_email_regex, remove_slurs, has_slurs};
#[test] #[test]
fn test_api() { fn test_api() {
assert_eq!(Settings::get().api_endpoint(), "http://0.0.0.0/api/v1"); assert_eq!(Settings::get().api_endpoint(), "http://0.0.0.0/api/v1");
} }
#[test] #[test] fn test_email() {
fn test_email() {
assert!(is_email_regex("gush@gmail.com")); assert!(is_email_regex("gush@gmail.com"));
assert!(!is_email_regex("nada_neutho")); 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();
}

View file

@ -10,7 +10,7 @@ use serde_json::{Value};
use bcrypt::{verify}; use bcrypt::{verify};
use std::str::FromStr; 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::community::*;
use actions::user::*; use actions::user::*;
use actions::post::*; use actions::post::*;
@ -541,6 +541,10 @@ impl Perform for Register {
return self.error("Passwords do not match."); return self.error("Passwords do not match.");
} }
if has_slurs(&self.username) {
return self.error("No slurs");
}
// Register the new user // Register the new user
let user_form = UserForm { let user_form = UserForm {
name: self.username.to_owned(), 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; let user_id = claims.id;
// When you create a community, make sure the user becomes a moderator and a follower // 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 user_id = claims.id;
let post_form = PostForm { let post_form = PostForm {
@ -894,8 +909,10 @@ impl Perform for CreateComment {
let user_id = claims.id; let user_id = claims.id;
let content_slurs_removed = remove_slurs(&self.content.to_owned());
let comment_form = CommentForm { let comment_form = CommentForm {
content: self.content.to_owned(), content: content_slurs_removed,
parent_id: self.parent_id.to_owned(), parent_id: self.parent_id.to_owned(),
post_id: self.post_id, post_id: self.post_id,
creator_id: user_id, creator_id: user_id,
@ -976,8 +993,10 @@ impl Perform for EditComment {
return self.error("Incorrect creator."); return self.error("Incorrect creator.");
} }
let content_slurs_removed = remove_slurs(&self.content.to_owned());
let comment_form = CommentForm { let comment_form = CommentForm {
content: self.content.to_owned(), content: content_slurs_removed,
parent_id: self.parent_id, parent_id: self.parent_id,
post_id: self.post_id, post_id: self.post_id,
creator_id: user_id, creator_id: user_id,
@ -1197,6 +1216,11 @@ impl Perform for EditPost {
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { 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 conn = establish_connection();
let claims = match Claims::decode(&self.auth) { let claims = match Claims::decode(&self.auth) {
@ -1264,6 +1288,10 @@ impl Perform for EditCommunity {
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { 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 conn = establish_connection();
let claims = match Claims::decode(&self.auth) { let claims = match Claims::decode(&self.auth) {

View file

@ -155,6 +155,7 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt
if (msg.error) { if (msg.error) {
alert(msg.error); alert(msg.error);
this.state.loading = false; this.state.loading = false;
this.setState(this.state);
return; return;
} else if (op == UserOperation.ListCategories){ } else if (op == UserOperation.ListCategories){
let res: ListCategoriesResponse = msg; let res: ListCategoriesResponse = msg;

View file

@ -97,7 +97,7 @@ export class Login extends Component<any, State> {
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label">Username</label> <label class="col-sm-2 col-form-label">Username</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" class="form-control" value={this.state.registerForm.username} onInput={linkEvent(this, this.handleRegisterUsernameChange)} required minLength={3} /> <input type="text" class="form-control" value={this.state.registerForm.username} onInput={linkEvent(this, this.handleRegisterUsernameChange)} required minLength={3} pattern="[a-zA-Z0-9_]+" />
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">

View file

@ -151,7 +151,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op: UserOperation = msgOp(msg); let op: UserOperation = msgOp(msg);
if (msg.error) { if (msg.error) {
alert(msg.error);
this.state.loading = false; this.state.loading = false;
this.setState(this.state);
return; return;
} else if (op == UserOperation.ListCommunities) { } else if (op == UserOperation.ListCommunities) {
let res: ListCommunitiesResponse = msg; let res: ListCommunitiesResponse = msg;