Sanitize HTML from API inputs
This commit is contained in:
parent
0da2fd3d93
commit
f53234d6a2
6 changed files with 71 additions and 30 deletions
|
@ -4,6 +4,7 @@ use chrono::{DateTime, FixedOffset, Local, NaiveDateTime};
|
|||
use itertools::Itertools;
|
||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use url::Url;
|
||||
|
||||
lazy_static! {
|
||||
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
|
||||
|
@ -128,3 +129,14 @@ pub fn get_ip(conn_info: &ConnectionInfo) -> String {
|
|||
.unwrap_or("127.0.0.1")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn is_valid_url_opt(value: &Option<String>) -> Result<(), APIError> {
|
||||
if let Some(v) = value {
|
||||
match Url::parse(v) {
|
||||
Ok(_t) => Ok(()),
|
||||
Err(_e) => Err(APIError::err("invalid_url")),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
LemmyContext,
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
use ammonia::clean_text;
|
||||
use lemmy_db::{
|
||||
comment::*,
|
||||
comment_view::*,
|
||||
|
@ -54,7 +55,7 @@ impl Perform for CreateComment {
|
|||
let content_slurs_removed = remove_slurs(&data.content.to_owned());
|
||||
|
||||
let comment_form = CommentForm {
|
||||
content: content_slurs_removed,
|
||||
content: clean_text(&content_slurs_removed),
|
||||
parent_id: data.parent_id.to_owned(),
|
||||
post_id: data.post_id,
|
||||
creator_id: user.id,
|
||||
|
@ -364,7 +365,7 @@ impl Perform for RemoveComment {
|
|||
mod_user_id: user.id,
|
||||
comment_id: data.edit_id,
|
||||
removed: Some(removed),
|
||||
reason: data.reason.to_owned(),
|
||||
reason: data.reason.as_ref().map(|r| clean_text(r)),
|
||||
};
|
||||
blocking(context.pool(), move |conn| {
|
||||
ModRemoveComment::create(conn, &form)
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
|||
LemmyContext,
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
use ammonia::clean_text;
|
||||
use anyhow::Context;
|
||||
use lemmy_db::{
|
||||
comment::Comment,
|
||||
|
@ -35,7 +36,13 @@ use lemmy_structs::{
|
|||
use lemmy_utils::{
|
||||
apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
|
||||
location_info,
|
||||
utils::{check_slurs, check_slurs_opt, is_valid_community_name, naive_from_unix},
|
||||
utils::{
|
||||
check_slurs,
|
||||
check_slurs_opt,
|
||||
is_valid_community_name,
|
||||
is_valid_url_opt,
|
||||
naive_from_unix,
|
||||
},
|
||||
APIError,
|
||||
ConnectionId,
|
||||
LemmyError,
|
||||
|
@ -139,10 +146,13 @@ impl Perform for CreateCommunity {
|
|||
// When you create a community, make sure the user becomes a moderator and a follower
|
||||
let keypair = generate_actor_keypair()?;
|
||||
|
||||
is_valid_url_opt(&data.icon)?;
|
||||
is_valid_url_opt(&data.banner)?;
|
||||
|
||||
let community_form = CommunityForm {
|
||||
name: data.name.to_owned(),
|
||||
title: data.title.to_owned(),
|
||||
description: data.description.to_owned(),
|
||||
name: clean_text(&data.name),
|
||||
title: clean_text(&data.title),
|
||||
description: data.description.as_ref().map(|d| clean_text(d)),
|
||||
icon: Some(data.icon.to_owned()),
|
||||
banner: Some(data.banner.to_owned()),
|
||||
category_id: data.category_id,
|
||||
|
@ -233,10 +243,13 @@ impl Perform for EditCommunity {
|
|||
let icon = diesel_option_overwrite(&data.icon);
|
||||
let banner = diesel_option_overwrite(&data.banner);
|
||||
|
||||
is_valid_url_opt(&data.icon)?;
|
||||
is_valid_url_opt(&data.banner)?;
|
||||
|
||||
let community_form = CommunityForm {
|
||||
name: read_community.name,
|
||||
title: data.title.to_owned(),
|
||||
description: data.description.to_owned(),
|
||||
name: clean_text(&read_community.name),
|
||||
title: clean_text(&data.title),
|
||||
description: data.description.as_ref().map(|d| clean_text(d)),
|
||||
icon,
|
||||
banner,
|
||||
category_id: data.category_id.to_owned(),
|
||||
|
@ -375,7 +388,7 @@ impl Perform for RemoveCommunity {
|
|||
mod_user_id: user.id,
|
||||
community_id: data.edit_id,
|
||||
removed: Some(removed),
|
||||
reason: data.reason.to_owned(),
|
||||
reason: data.reason.as_ref().map(|r| clean_text(r)),
|
||||
expires,
|
||||
};
|
||||
blocking(context.pool(), move |conn| {
|
||||
|
@ -611,7 +624,7 @@ impl Perform for BanFromCommunity {
|
|||
mod_user_id: user.id,
|
||||
other_user_id: data.user_id,
|
||||
community_id: data.community_id,
|
||||
reason: data.reason.to_owned(),
|
||||
reason: data.reason.as_ref().map(|r| clean_text(r)),
|
||||
banned: Some(data.ban),
|
||||
expires,
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
LemmyContext,
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
use ammonia::clean_text;
|
||||
use lemmy_db::{
|
||||
comment_view::*,
|
||||
community_view::*,
|
||||
|
@ -67,9 +68,9 @@ impl Perform for CreatePost {
|
|||
fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await;
|
||||
|
||||
let post_form = PostForm {
|
||||
name: data.name.trim().to_owned(),
|
||||
name: clean_text(&data.name.trim()),
|
||||
url: data.url.to_owned(),
|
||||
body: data.body.to_owned(),
|
||||
body: data.body.as_ref().map(|b| clean_text(&b)),
|
||||
community_id: data.community_id,
|
||||
creator_id: user.id,
|
||||
removed: None,
|
||||
|
@ -379,9 +380,9 @@ impl Perform for EditPost {
|
|||
fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await;
|
||||
|
||||
let post_form = PostForm {
|
||||
name: data.name.trim().to_owned(),
|
||||
name: clean_text(&data.name.trim()),
|
||||
url: data.url.to_owned(),
|
||||
body: data.body.to_owned(),
|
||||
body: data.body.as_ref().map(|b| clean_text(b)),
|
||||
nsfw: data.nsfw,
|
||||
creator_id: orig_post.creator_id.to_owned(),
|
||||
community_id: orig_post.community_id,
|
||||
|
@ -527,7 +528,7 @@ impl Perform for RemovePost {
|
|||
mod_user_id: user.id,
|
||||
post_id: data.edit_id,
|
||||
removed: Some(removed),
|
||||
reason: data.reason.to_owned(),
|
||||
reason: data.reason.as_ref().map(|r| clean_text(r)),
|
||||
};
|
||||
blocking(context.pool(), move |conn| {
|
||||
ModRemovePost::create(conn, &form)
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
LemmyContext,
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
use ammonia::clean_text;
|
||||
use anyhow::Context;
|
||||
use lemmy_db::{
|
||||
category::*,
|
||||
|
@ -31,7 +32,7 @@ use lemmy_structs::{
|
|||
use lemmy_utils::{
|
||||
location_info,
|
||||
settings::Settings,
|
||||
utils::{check_slurs, check_slurs_opt},
|
||||
utils::{check_slurs, check_slurs_opt, is_valid_url_opt},
|
||||
APIError,
|
||||
ConnectionId,
|
||||
LemmyError,
|
||||
|
@ -155,9 +156,12 @@ impl Perform for CreateSite {
|
|||
// Make sure user is an admin
|
||||
is_admin(context.pool(), user.id).await?;
|
||||
|
||||
is_valid_url_opt(&data.icon)?;
|
||||
is_valid_url_opt(&data.banner)?;
|
||||
|
||||
let site_form = SiteForm {
|
||||
name: data.name.to_owned(),
|
||||
description: data.description.to_owned(),
|
||||
name: clean_text(&data.name),
|
||||
description: data.description.as_ref().map(|d| clean_text(d)),
|
||||
icon: Some(data.icon.to_owned()),
|
||||
banner: Some(data.banner.to_owned()),
|
||||
creator_id: user.id,
|
||||
|
@ -197,12 +201,15 @@ impl Perform for EditSite {
|
|||
|
||||
let found_site = blocking(context.pool(), move |conn| Site::read(conn, 1)).await??;
|
||||
|
||||
is_valid_url_opt(&data.icon)?;
|
||||
is_valid_url_opt(&data.banner)?;
|
||||
|
||||
let icon = diesel_option_overwrite(&data.icon);
|
||||
let banner = diesel_option_overwrite(&data.banner);
|
||||
|
||||
let site_form = SiteForm {
|
||||
name: data.name.to_owned(),
|
||||
description: data.description.to_owned(),
|
||||
name: clean_text(&data.name.to_owned()),
|
||||
description: data.description.as_ref().map(|d| clean_text(d)),
|
||||
icon,
|
||||
banner,
|
||||
creator_id: found_site.creator_id,
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
LemmyContext,
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
use ammonia::clean_text;
|
||||
use anyhow::Context;
|
||||
use bcrypt::verify;
|
||||
use captcha::{gen, Difficulty};
|
||||
|
@ -55,6 +56,7 @@ use lemmy_utils::{
|
|||
check_slurs,
|
||||
generate_random_string,
|
||||
is_valid_preferred_username,
|
||||
is_valid_url_opt,
|
||||
is_valid_username,
|
||||
naive_from_unix,
|
||||
remove_slurs,
|
||||
|
@ -160,11 +162,12 @@ impl Perform for Register {
|
|||
if !is_valid_username(&data.username) {
|
||||
return Err(APIError::err("invalid_username").into());
|
||||
}
|
||||
let email = data.email.as_ref().map(|e| clean_text(e));
|
||||
|
||||
// Register the new user
|
||||
let user_form = UserForm {
|
||||
name: data.username.to_owned(),
|
||||
email: Some(data.email.to_owned()),
|
||||
name: clean_text(&data.username),
|
||||
email: Some(email),
|
||||
matrix_user_id: None,
|
||||
avatar: None,
|
||||
banner: None,
|
||||
|
@ -217,7 +220,7 @@ impl Perform for Register {
|
|||
Err(_e) => {
|
||||
let default_community_name = "main";
|
||||
let community_form = CommunityForm {
|
||||
name: default_community_name.to_string(),
|
||||
name: clean_text(default_community_name),
|
||||
title: "The Default Community".to_string(),
|
||||
description: Some("The Default Community".to_string()),
|
||||
category_id: 1,
|
||||
|
@ -340,7 +343,7 @@ impl Perform for SaveUserSettings {
|
|||
let bio = match &data.bio {
|
||||
Some(bio) => {
|
||||
if bio.chars().count() <= 300 {
|
||||
Some(bio.to_owned())
|
||||
Some(clean_text(&bio.to_owned()))
|
||||
} else {
|
||||
return Err(APIError::err("bio_length_overflow").into());
|
||||
}
|
||||
|
@ -350,7 +353,11 @@ impl Perform for SaveUserSettings {
|
|||
|
||||
let avatar = diesel_option_overwrite(&data.avatar);
|
||||
let banner = diesel_option_overwrite(&data.banner);
|
||||
let email = diesel_option_overwrite(&data.email);
|
||||
let email = data.email.as_ref().map(|e| clean_text(e));
|
||||
let email = diesel_option_overwrite(&email);
|
||||
|
||||
is_valid_url_opt(&data.avatar)?;
|
||||
is_valid_url_opt(&data.banner)?;
|
||||
|
||||
// The DB constraint should stop too many characters
|
||||
let preferred_username = match &data.preferred_username {
|
||||
|
@ -397,9 +404,9 @@ impl Perform for SaveUserSettings {
|
|||
};
|
||||
|
||||
let user_form = UserForm {
|
||||
name: read_user.name,
|
||||
name: clean_text(&read_user.name),
|
||||
email,
|
||||
matrix_user_id: data.matrix_user_id.to_owned(),
|
||||
matrix_user_id: data.matrix_user_id.as_ref().map(|m| clean_text(m)),
|
||||
avatar,
|
||||
banner,
|
||||
password_encrypted,
|
||||
|
@ -654,7 +661,7 @@ impl Perform for BanUser {
|
|||
let form = ModBanForm {
|
||||
mod_user_id: user.id,
|
||||
other_user_id: data.user_id,
|
||||
reason: data.reason.to_owned(),
|
||||
reason: data.reason.as_ref().map(|r| clean_text(r)),
|
||||
banned: Some(data.ban),
|
||||
expires,
|
||||
};
|
||||
|
@ -983,7 +990,7 @@ impl Perform for CreatePrivateMessage {
|
|||
let content_slurs_removed = remove_slurs(&data.content.to_owned());
|
||||
|
||||
let private_message_form = PrivateMessageForm {
|
||||
content: content_slurs_removed.to_owned(),
|
||||
content: clean_text(&content_slurs_removed),
|
||||
creator_id: user.id,
|
||||
recipient_id: data.recipient_id,
|
||||
deleted: None,
|
||||
|
|
Loading…
Reference in a new issue