You've already forked AstralRinth
forked from didirus/AstralRinth
Add auto-reporting inappropriate text content (#387)
* Add initial support for blocking inappropriate text content To make something clear, **nothing** is automatically censored or deleted as a result of this pull request. This pull request is meant to add two things: - Regenerate new IDs (project, version, user, etc.) with profanity - Send reports to the moderators for new inappropriate content * Make it build * Fix logic issue Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -584,6 +584,15 @@ dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "censor"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5563d2728feef9a6186acdd148bccbe850dad63c5ba55a3b3355abc9137cb3eb"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -1456,6 +1465,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"cached",
|
||||
"censor",
|
||||
"dashmap",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
|
||||
@@ -63,4 +63,6 @@ bytes = "1.1.0"
|
||||
|
||||
dashmap = "5.2.0"
|
||||
|
||||
cached = "0.34.0"
|
||||
cached = "0.34.0"
|
||||
|
||||
censor = "0.2.0"
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::DatabaseError;
|
||||
use crate::models::ids::base62_impl::to_base62;
|
||||
use crate::models::ids::random_base62_rng;
|
||||
use censor::Censor;
|
||||
use sqlx::sqlx_macros::Type;
|
||||
|
||||
const ID_RETRY_COUNT: usize = 20;
|
||||
@@ -13,6 +15,7 @@ macro_rules! generate_ids {
|
||||
let length = $id_length;
|
||||
let mut id = random_base62_rng(&mut rng, length);
|
||||
let mut retry_count = 0;
|
||||
let censor = Censor::Standard + Censor::Sex;
|
||||
|
||||
// Check if ID is unique
|
||||
loop {
|
||||
@@ -20,7 +23,7 @@ macro_rules! generate_ids {
|
||||
.fetch_one(&mut *con)
|
||||
.await?;
|
||||
|
||||
if results.exists.unwrap_or(true) {
|
||||
if results.exists.unwrap_or(true) || censor.check(&*to_base62(id)) {
|
||||
id = random_base62_rng(&mut rng, length);
|
||||
} else {
|
||||
break;
|
||||
|
||||
@@ -247,19 +247,52 @@ pub async fn auth_callback(
|
||||
}
|
||||
|
||||
if let Some(username) = username {
|
||||
User {
|
||||
let new_user = User {
|
||||
id: user_id,
|
||||
github_id: Some(user.id as i64),
|
||||
username,
|
||||
username: username.clone(),
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
avatar_url: Some(user.avatar_url),
|
||||
bio: user.bio,
|
||||
created: OffsetDateTime::now_utc(),
|
||||
role: Role::Developer.to_string(),
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
};
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*username,
|
||||
None,
|
||||
None,
|
||||
Some(user_id),
|
||||
"New user's username is inappropriate".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(name) = &new_user.name {
|
||||
crate::util::report::censor_check(
|
||||
&*name,
|
||||
None,
|
||||
None,
|
||||
Some(user_id),
|
||||
"New user's name is inappropriate".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(bio) = &new_user.bio {
|
||||
crate::util::report::censor_check(
|
||||
&*bio,
|
||||
None,
|
||||
None,
|
||||
Some(user_id),
|
||||
"New user's bio is inappropriate".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
new_user.insert(&mut transaction).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +387,16 @@ pub async fn project_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*title,
|
||||
Some(project_item.inner.id),
|
||||
None,
|
||||
None,
|
||||
"Project edited with inappropriate title".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(description) = &new_project.description {
|
||||
@@ -408,6 +418,16 @@ pub async fn project_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*description,
|
||||
Some(project_item.inner.id),
|
||||
None,
|
||||
None,
|
||||
"Project edited with inappropriate description".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(status) = &new_project.status {
|
||||
@@ -679,6 +699,16 @@ pub async fn project_edit(
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*slug,
|
||||
Some(project_item.inner.id),
|
||||
None,
|
||||
None,
|
||||
"Project edited with inappropriate slug".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
@@ -891,6 +921,16 @@ pub async fn project_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*body,
|
||||
Some(project_item.inner.id),
|
||||
None,
|
||||
None,
|
||||
"Project edited with inappropriate body".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
transaction.commit().await?;
|
||||
|
||||
@@ -204,6 +204,18 @@ pub async fn user_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*username,
|
||||
None,
|
||||
None,
|
||||
Some(crate::database::models::ids::UserId::from(
|
||||
user_id,
|
||||
)),
|
||||
"User edited with inappropriate username".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
return Err(ApiError::InvalidInput(format!(
|
||||
"Username {} is taken!",
|
||||
@@ -224,6 +236,20 @@ pub async fn user_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
if let Some(name) = name {
|
||||
crate::util::report::censor_check(
|
||||
&*name,
|
||||
None,
|
||||
None,
|
||||
Some(crate::database::models::ids::UserId::from(
|
||||
user_id,
|
||||
)),
|
||||
"User edited with inappropriate name".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bio) = &new_user.bio {
|
||||
@@ -238,6 +264,20 @@ pub async fn user_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
if let Some(bio) = bio {
|
||||
crate::util::report::censor_check(
|
||||
&*bio,
|
||||
None,
|
||||
None,
|
||||
Some(crate::database::models::ids::UserId::from(
|
||||
user_id,
|
||||
)),
|
||||
"User edited with inappropriate bio".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(email) = &new_user.email {
|
||||
|
||||
@@ -393,6 +393,28 @@ async fn version_create_inner(
|
||||
.insert_many(users, &mut *transaction)
|
||||
.await?;
|
||||
|
||||
if let Some(version_body) = version_data.version_body {
|
||||
crate::util::report::censor_check(
|
||||
&*version_body,
|
||||
None,
|
||||
Some(models::ids::VersionId::from(version_id)),
|
||||
None,
|
||||
"Version created with inappropriate changelog".to_string(),
|
||||
&mut *transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*version_data.version_title,
|
||||
None,
|
||||
Some(models::ids::VersionId::from(version_id)),
|
||||
None,
|
||||
"Version created with inappropriate name".to_string(),
|
||||
&mut *transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let response = Version {
|
||||
id: builder.version_id.into(),
|
||||
project_id: builder.project_id.into(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::ApiError;
|
||||
use crate::database;
|
||||
use crate::database::models::VersionId;
|
||||
use crate::models;
|
||||
use crate::models::projects::{Dependency, Version};
|
||||
use crate::models::teams::Permissions;
|
||||
@@ -247,6 +248,16 @@ pub async fn version_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*name,
|
||||
None,
|
||||
Some(VersionId::from(version_id)),
|
||||
None,
|
||||
"Version edited with inappropriate name".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(number) = &new_version.version_number {
|
||||
@@ -463,6 +474,16 @@ pub async fn version_edit(
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
crate::util::report::censor_check(
|
||||
&*body,
|
||||
None,
|
||||
Some(VersionId::from(version_id)),
|
||||
None,
|
||||
"Version edited with inappropriate changelog".to_string(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(downloads) = &new_version.downloads {
|
||||
|
||||
@@ -2,6 +2,7 @@ pub mod auth;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod guards;
|
||||
pub mod report;
|
||||
pub mod routes;
|
||||
pub mod time_ser;
|
||||
pub mod validate;
|
||||
|
||||
38
src/util/report.rs
Normal file
38
src/util/report.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use crate::database::models::categories::ReportType;
|
||||
use crate::database::models::report_item::Report;
|
||||
use crate::database::models::{
|
||||
generate_report_id, DatabaseError, ProjectId, UserId, VersionId,
|
||||
};
|
||||
use crate::models::users::DELETED_USER;
|
||||
use censor::Censor;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub async fn censor_check(
|
||||
text: &str,
|
||||
project: Option<ProjectId>,
|
||||
version: Option<VersionId>,
|
||||
user: Option<UserId>,
|
||||
report_text: String,
|
||||
mut transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let censor = Censor::Standard + Censor::Sex;
|
||||
if censor.check(text) {
|
||||
let report_type =
|
||||
ReportType::get_id("inappropriate", &mut *transaction)
|
||||
.await?
|
||||
.expect("No database entry for 'inappropriate' report type");
|
||||
Report {
|
||||
id: generate_report_id(&mut transaction).await?,
|
||||
report_type_id: report_type,
|
||||
project_id: project,
|
||||
version_id: version,
|
||||
user_id: user,
|
||||
body: report_text,
|
||||
reporter: UserId::from(DELETED_USER),
|
||||
created: OffsetDateTime::now_utc(),
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user