]> Untitled Git - lemmy.git/commitdiff
Adding check to description and body length fields. (#2805)
authorDessalines <dessalines@users.noreply.github.com>
Sat, 15 Apr 2023 14:45:11 +0000 (10:45 -0400)
committerGitHub <noreply@github.com>
Sat, 15 Apr 2023 14:45:11 +0000 (10:45 -0400)
* Adding check to description and body length fields.

- Also making the checks return `LemmyError`
- Fixes #1747

* Address PR comments.

* PR comments 2

15 files changed:
crates/api/src/community/ban.rs
crates/api/src/local_user/ban_person.rs
crates/api/src/local_user/save_settings.rs
crates/api_crud/src/comment/create.rs
crates/api_crud/src/comment/update.rs
crates/api_crud/src/community/create.rs
crates/api_crud/src/community/update.rs
crates/api_crud/src/post/create.rs
crates/api_crud/src/post/update.rs
crates/api_crud/src/private_message/create.rs
crates/api_crud/src/private_message/update.rs
crates/api_crud/src/site/create.rs
crates/api_crud/src/site/update.rs
crates/api_crud/src/user/create.rs
crates/utils/src/utils/validation.rs

index d3341340e297440a7729612b6c4c4f577b0a145c..c19df91ff9fc19c514d25a4d3e96c76898906596 100644 (file)
@@ -23,7 +23,11 @@ use lemmy_db_schema::{
   traits::{Bannable, Crud, Followable},
 };
 use lemmy_db_views_actor::structs::PersonView;
-use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{time::naive_from_unix, validation::is_valid_body_field},
+  ConnectionId,
+};
 
 #[async_trait::async_trait(?Send)]
 impl Perform for BanFromCommunity {
@@ -46,6 +50,7 @@ impl Perform for BanFromCommunity {
 
     // Verify that only mods or admins can ban
     is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?;
+    is_valid_body_field(&data.reason)?;
 
     let community_user_ban_form = CommunityPersonBanForm {
       community_id: data.community_id,
index 55069742c49799bdd0836836cd5971dcfc45f5a8..d2b780433af116fae07907f77970d0af0250f165 100644 (file)
@@ -14,7 +14,11 @@ use lemmy_db_schema::{
   traits::Crud,
 };
 use lemmy_db_views_actor::structs::PersonView;
-use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{time::naive_from_unix, validation::is_valid_body_field},
+  ConnectionId,
+};
 
 #[async_trait::async_trait(?Send)]
 impl Perform for BanPerson {
@@ -33,6 +37,8 @@ impl Perform for BanPerson {
     // Make sure user is an admin
     is_admin(&local_user_view)?;
 
+    is_valid_body_field(&data.reason)?;
+
     let ban = data.ban;
     let banned_person_id = data.person_id;
     let expires = data.expires.map(naive_from_unix);
index e3c95a3d3f4c1025ff59bee27b490ae34d4b7cf7..0221d0ce207658c8154e09244de0e8f5efd1906c 100644 (file)
@@ -21,6 +21,7 @@ use lemmy_utils::{
   utils::validation::{
     build_totp_2fa,
     generate_totp_2fa_secret,
+    is_valid_bio_field,
     is_valid_display_name,
     is_valid_matrix_id,
   },
@@ -67,24 +68,18 @@ impl Perform for SaveUserSettings {
     }
 
     if let Some(Some(bio)) = &bio {
-      if bio.chars().count() > 300 {
-        return Err(LemmyError::from_message("bio_length_overflow"));
-      }
+      is_valid_bio_field(bio)?;
     }
 
     if let Some(Some(display_name)) = &display_name {
-      if !is_valid_display_name(
+      is_valid_display_name(
         display_name.trim(),
         site_view.local_site.actor_name_max_length as usize,
-      ) {
-        return Err(LemmyError::from_message("invalid_username"));
-      }
+      )?;
     }
 
     if let Some(Some(matrix_user_id)) = &matrix_user_id {
-      if !is_valid_matrix_id(matrix_user_id) {
-        return Err(LemmyError::from_message("invalid_matrix_id"));
-      }
+      is_valid_matrix_id(matrix_user_id)?;
     }
 
     let local_user_id = local_user_view.local_user.id;
index 70997378dc80d3d90d4022ec26638fdf36a408f4..511059ac98b25d09269f7ca7c0973f09c891f4ba 100644 (file)
@@ -27,7 +27,11 @@ use lemmy_db_schema::{
 };
 use lemmy_utils::{
   error::LemmyError,
-  utils::{mention::scrape_text_for_mentions, slurs::remove_slurs},
+  utils::{
+    mention::scrape_text_for_mentions,
+    slurs::remove_slurs,
+    validation::is_valid_body_field,
+  },
   ConnectionId,
 };
 
@@ -50,6 +54,7 @@ impl PerformCrud for CreateComment {
       &data.content.clone(),
       &local_site_to_slur_regex(&local_site),
     );
+    is_valid_body_field(&Some(content_slurs_removed.clone()))?;
 
     // Check for a community ban
     let post_id = data.post_id;
index 1d5f1c5a2745b6492039fc6cbdaece1785797350..1d6d0869dde73d1ed1de30221ff18e21e2cc84bd 100644 (file)
@@ -18,7 +18,11 @@ use lemmy_db_schema::{
 use lemmy_db_views::structs::CommentView;
 use lemmy_utils::{
   error::LemmyError,
-  utils::{mention::scrape_text_for_mentions, slurs::remove_slurs},
+  utils::{
+    mention::scrape_text_for_mentions,
+    slurs::remove_slurs,
+    validation::is_valid_body_field,
+  },
   ConnectionId,
 };
 
@@ -65,6 +69,9 @@ impl PerformCrud for EditComment {
       .content
       .as_ref()
       .map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
+
+    is_valid_body_field(&content_slurs_removed)?;
+
     let comment_id = data.comment_id;
     let form = CommentUpdateForm::builder()
       .content(content_slurs_removed)
index 907cf1b20c060351887998415cbd810d0e1d180d..e2e80b8492bbd3448c91b4b7647a1cf2d4ba44f7 100644 (file)
@@ -36,7 +36,7 @@ use lemmy_utils::{
   error::LemmyError,
   utils::{
     slurs::{check_slurs, check_slurs_opt},
-    validation::is_valid_actor_name,
+    validation::{is_valid_actor_name, is_valid_body_field},
   },
   ConnectionId,
 };
@@ -72,9 +72,8 @@ impl PerformCrud for CreateCommunity {
     check_slurs(&data.title, &slur_regex)?;
     check_slurs_opt(&data.description, &slur_regex)?;
 
-    if !is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize) {
-      return Err(LemmyError::from_message("invalid_community_name"));
-    }
+    is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?;
+    is_valid_body_field(&data.description)?;
 
     // Double check for duplicate community actor_ids
     let community_actor_id = generate_local_apub_endpoint(
index 9628615bbb56d22792d725715ba4d7da77e961cb..200c5f2c83898401ac8d08c2c66717a81edbabf5 100644 (file)
@@ -17,7 +17,11 @@ use lemmy_db_schema::{
   utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
 };
 use lemmy_db_views_actor::structs::CommunityModeratorView;
-use lemmy_utils::{error::LemmyError, utils::slurs::check_slurs_opt, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{slurs::check_slurs_opt, validation::is_valid_body_field},
+  ConnectionId,
+};
 
 #[async_trait::async_trait(?Send)]
 impl PerformCrud for EditCommunity {
@@ -41,6 +45,7 @@ impl PerformCrud for EditCommunity {
     let slur_regex = local_site_to_slur_regex(&local_site);
     check_slurs_opt(&data.title, &slur_regex)?;
     check_slurs_opt(&data.description, &slur_regex)?;
+    is_valid_body_field(&data.description)?;
 
     // Verify its a mod (only mods can edit it)
     let community_id = data.community_id;
index 2ceade21f6303d3a1df258fbeb794d210b96fea2..1a88518472fa9608acbe2f5eb2afea83b9326e29 100644 (file)
@@ -31,7 +31,7 @@ use lemmy_utils::{
   error::LemmyError,
   utils::{
     slurs::{check_slurs, check_slurs_opt},
-    validation::{clean_url_params, is_valid_post_title},
+    validation::{clean_url_params, is_valid_body_field, is_valid_post_title},
   },
   ConnectionId,
 };
@@ -62,9 +62,8 @@ impl PerformCrud for CreatePost {
     let data_url = data.url.as_ref();
     let url = data_url.map(clean_url_params).map(Into::into); // TODO no good way to handle a "clear"
 
-    if !is_valid_post_title(&data.name) {
-      return Err(LemmyError::from_message("invalid_post_title"));
-    }
+    is_valid_post_title(&data.name)?;
+    is_valid_body_field(&data.body)?;
 
     check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?;
     check_community_deleted_or_removed(data.community_id, context.pool()).await?;
index 27cfabe5b8f4b56a5b903fe7f27bb0773de241f6..8f5c442fcf853a80eb515e31a75003592c971f50 100644 (file)
@@ -20,7 +20,7 @@ use lemmy_utils::{
   error::LemmyError,
   utils::{
     slurs::check_slurs_opt,
-    validation::{clean_url_params, is_valid_post_title},
+    validation::{clean_url_params, is_valid_body_field, is_valid_post_title},
   },
   ConnectionId,
 };
@@ -52,11 +52,11 @@ impl PerformCrud for EditPost {
     check_slurs_opt(&data.body, &slur_regex)?;
 
     if let Some(name) = &data.name {
-      if !is_valid_post_title(name) {
-        return Err(LemmyError::from_message("invalid_post_title"));
-      }
+      is_valid_post_title(name)?;
     }
 
+    is_valid_body_field(&data.body)?;
+
     let post_id = data.post_id;
     let orig_post = Post::read(context.pool(), post_id).await?;
 
index 28c243f6549f6d135129c490a6e986be21f5ddca..48fa840236c2306de54d071e85cd931c0810e0ab 100644 (file)
@@ -22,7 +22,11 @@ use lemmy_db_schema::{
   traits::Crud,
 };
 use lemmy_db_views::structs::LocalUserView;
-use lemmy_utils::{error::LemmyError, utils::slurs::remove_slurs, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{slurs::remove_slurs, validation::is_valid_body_field},
+  ConnectionId,
+};
 
 #[async_trait::async_trait(?Send)]
 impl PerformCrud for CreatePrivateMessage {
@@ -43,6 +47,7 @@ impl PerformCrud for CreatePrivateMessage {
       &data.content.clone(),
       &local_site_to_slur_regex(&local_site),
     );
+    is_valid_body_field(&Some(content_slurs_removed.clone()))?;
 
     check_person_block(local_user_view.person.id, data.recipient_id, context.pool()).await?;
 
index 06bd349f4cbbabcb277bcbc2cedfc34c463335c3..6a6bfa21831539d3a7b5b3600d96d9edf3afd975 100644 (file)
@@ -14,7 +14,11 @@ use lemmy_db_schema::{
   traits::Crud,
   utils::naive_now,
 };
-use lemmy_utils::{error::LemmyError, utils::slurs::remove_slurs, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{slurs::remove_slurs, validation::is_valid_body_field},
+  ConnectionId,
+};
 
 #[async_trait::async_trait(?Send)]
 impl PerformCrud for EditPrivateMessage {
@@ -40,6 +44,8 @@ impl PerformCrud for EditPrivateMessage {
 
     // Doing the update
     let content_slurs_removed = remove_slurs(&data.content, &local_site_to_slur_regex(&local_site));
+    is_valid_body_field(&Some(content_slurs_removed.clone()))?;
+
     let private_message_id = data.private_message_id;
     PrivateMessage::update(
       context.pool(),
index bda7eadc9fb03b2e7946b42db9b03bc67517e559..ecafa9b2c19e09dee413abe43a9ce677977f02d8 100644 (file)
@@ -26,7 +26,10 @@ use lemmy_db_schema::{
 use lemmy_db_views::structs::SiteView;
 use lemmy_utils::{
   error::LemmyError,
-  utils::slurs::{check_slurs, check_slurs_opt},
+  utils::{
+    slurs::{check_slurs, check_slurs_opt},
+    validation::is_valid_body_field,
+  },
   ConnectionId,
 };
 use url::Url;
@@ -68,6 +71,8 @@ impl PerformCrud for CreateSite {
       site_description_length_check(desc)?;
     }
 
+    is_valid_body_field(&data.sidebar)?;
+
     let application_question = diesel_option_overwrite(&data.application_question);
     check_application_question(
       &application_question,
index 3922fdab7a4f0b9d55545a2a21a779306537174c..eb29a6dad8cdb383d5323f10f74ac61b4a3efab2 100644 (file)
@@ -28,7 +28,11 @@ use lemmy_db_schema::{
   ListingType,
 };
 use lemmy_db_views::structs::SiteView;
-use lemmy_utils::{error::LemmyError, utils::slurs::check_slurs_opt, ConnectionId};
+use lemmy_utils::{
+  error::LemmyError,
+  utils::{slurs::check_slurs_opt, validation::is_valid_body_field},
+  ConnectionId,
+};
 use std::str::FromStr;
 
 #[async_trait::async_trait(?Send)]
@@ -60,6 +64,8 @@ impl PerformCrud for EditSite {
       site_description_length_check(desc)?;
     }
 
+    is_valid_body_field(&data.sidebar)?;
+
     let application_question = diesel_option_overwrite(&data.application_question);
     check_application_question(
       &application_question,
index 0554da0557a9ccbf142451eb5f1f82e26151612b..f90393c2851034d4f127c75fdac70b6e255400f4 100644 (file)
@@ -96,9 +96,7 @@ impl PerformCrud for Register {
     check_slurs_opt(&data.answer, &slur_regex)?;
 
     let actor_keypair = generate_actor_keypair()?;
-    if !is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize) {
-      return Err(LemmyError::from_message("invalid_username"));
-    }
+    is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize)?;
     let actor_id = generate_local_apub_endpoint(
       EndpointType::Person,
       &data.username,
index 37838866d812efa00764016a17d6c6ed892b5528..c4feb467bb891e5ac31b2803d43361a338a87f2a 100644 (file)
@@ -1,4 +1,4 @@
-use crate::error::LemmyError;
+use crate::error::{LemmyError, LemmyResult};
 use itertools::Itertools;
 use once_cell::sync::Lazy;
 use regex::Regex;
@@ -17,32 +17,77 @@ static CLEAN_URL_PARAMS_REGEX: Lazy<Regex> = Lazy::new(|| {
   Regex::new(r"^utm_source|utm_medium|utm_campaign|utm_term|utm_content|gclid|gclsrc|dclid|fbclid$")
     .expect("compile regex")
 });
+const BODY_MAX_LENGTH: usize = 10000;
+const BIO_MAX_LENGTH: usize = 300;
 
 fn has_newline(name: &str) -> bool {
   name.contains('\n')
 }
 
-pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> bool {
-  name.chars().count() <= actor_name_max_length
+pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> LemmyResult<()> {
+  let check = name.chars().count() <= actor_name_max_length
     && VALID_ACTOR_NAME_REGEX.is_match(name)
-    && !has_newline(name)
+    && !has_newline(name);
+  if !check {
+    Err(LemmyError::from_message("invalid_name"))
+  } else {
+    Ok(())
+  }
 }
 
 // Can't do a regex here, reverse lookarounds not supported
-pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> bool {
-  !name.starts_with('@')
+pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> LemmyResult<()> {
+  let check = !name.starts_with('@')
     && !name.starts_with('\u{200b}')
     && name.chars().count() >= 3
     && name.chars().count() <= actor_name_max_length
-    && !has_newline(name)
+    && !has_newline(name);
+  if !check {
+    Err(LemmyError::from_message("invalid_username"))
+  } else {
+    Ok(())
+  }
+}
+
+pub fn is_valid_matrix_id(matrix_id: &str) -> LemmyResult<()> {
+  let check = VALID_MATRIX_ID_REGEX.is_match(matrix_id) && !has_newline(matrix_id);
+  if !check {
+    Err(LemmyError::from_message("invalid_matrix_id"))
+  } else {
+    Ok(())
+  }
 }
 
-pub fn is_valid_matrix_id(matrix_id: &str) -> bool {
-  VALID_MATRIX_ID_REGEX.is_match(matrix_id) && !has_newline(matrix_id)
+pub fn is_valid_post_title(title: &str) -> LemmyResult<()> {
+  let check = VALID_POST_TITLE_REGEX.is_match(title) && !has_newline(title);
+  if !check {
+    Err(LemmyError::from_message("invalid_post_title"))
+  } else {
+    Ok(())
+  }
 }
 
-pub fn is_valid_post_title(title: &str) -> bool {
-  VALID_POST_TITLE_REGEX.is_match(title) && !has_newline(title)
+/// This could be post bodies, comments, or any description field
+pub fn is_valid_body_field(body: &Option<String>) -> LemmyResult<()> {
+  if let Some(body) = body {
+    let check = body.chars().count() <= BODY_MAX_LENGTH;
+    if !check {
+      Err(LemmyError::from_message("invalid_body_field"))
+    } else {
+      Ok(())
+    }
+  } else {
+    Ok(())
+  }
+}
+
+pub fn is_valid_bio_field(bio: &str) -> LemmyResult<()> {
+  let check = bio.chars().count() <= BIO_MAX_LENGTH;
+  if !check {
+    Err(LemmyError::from_message("bio_length_overflow"))
+  } else {
+    Ok(())
+  }
 }
 
 pub fn clean_url_params(url: &Url) -> Url {
@@ -63,7 +108,7 @@ pub fn check_totp_2fa_valid(
   totp_token: &Option<String>,
   site_name: &str,
   username: &str,
-) -> Result<(), LemmyError> {
+) -> LemmyResult<()> {
   // Check only if they have a totp_secret in the DB
   if let Some(totp_secret) = totp_secret {
     // Throw an error if their token is missing
@@ -131,52 +176,48 @@ mod tests {
 
   #[test]
   fn regex_checks() {
-    assert!(!is_valid_post_title("hi"));
-    assert!(is_valid_post_title("him"));
-    assert!(!is_valid_post_title("n\n\n\n\nanother"));
-    assert!(!is_valid_post_title("hello there!\n this is a test."));
-    assert!(is_valid_post_title("hello there! this is a test."));
+    assert!(is_valid_post_title("hi").is_err());
+    assert!(is_valid_post_title("him").is_ok());
+    assert!(is_valid_post_title("n\n\n\n\nanother").is_err());
+    assert!(is_valid_post_title("hello there!\n this is a test.").is_err());
+    assert!(is_valid_post_title("hello there! this is a test.").is_ok());
   }
 
   #[test]
   fn test_valid_actor_name() {
     let actor_name_max_length = 20;
-    assert!(is_valid_actor_name("Hello_98", actor_name_max_length));
-    assert!(is_valid_actor_name("ten", actor_name_max_length));
-    assert!(!is_valid_actor_name("Hello-98", actor_name_max_length));
-    assert!(!is_valid_actor_name("a", actor_name_max_length));
-    assert!(!is_valid_actor_name("", actor_name_max_length));
+    assert!(is_valid_actor_name("Hello_98", actor_name_max_length).is_ok());
+    assert!(is_valid_actor_name("ten", actor_name_max_length).is_ok());
+    assert!(is_valid_actor_name("Hello-98", actor_name_max_length).is_err());
+    assert!(is_valid_actor_name("a", actor_name_max_length).is_err());
+    assert!(is_valid_actor_name("", actor_name_max_length).is_err());
   }
 
   #[test]
   fn test_valid_display_name() {
     let actor_name_max_length = 20;
-    assert!(is_valid_display_name("hello @there", actor_name_max_length));
-    assert!(!is_valid_display_name(
-      "@hello there",
-      actor_name_max_length
-    ));
+    assert!(is_valid_display_name("hello @there", actor_name_max_length).is_ok());
+    assert!(is_valid_display_name("@hello there", actor_name_max_length).is_err());
 
     // Make sure zero-space with an @ doesn't work
-    assert!(!is_valid_display_name(
-      &format!("{}@my name is", '\u{200b}'),
-      actor_name_max_length
-    ));
+    assert!(
+      is_valid_display_name(&format!("{}@my name is", '\u{200b}'), actor_name_max_length).is_err()
+    );
   }
 
   #[test]
   fn test_valid_post_title() {
-    assert!(is_valid_post_title("Post Title"));
-    assert!(is_valid_post_title("   POST TITLE ðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒ"));
-    assert!(!is_valid_post_title("\n \n \n \n                  ")); // tabs/spaces/newlines
+    assert!(is_valid_post_title("Post Title").is_ok());
+    assert!(is_valid_post_title("   POST TITLE ðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒ").is_ok());
+    assert!(is_valid_post_title("\n \n \n \n                   ").is_err()); // tabs/spaces/newlines
   }
 
   #[test]
   fn test_valid_matrix_id() {
-    assert!(is_valid_matrix_id("@dess:matrix.org"));
-    assert!(!is_valid_matrix_id("dess:matrix.org"));
-    assert!(!is_valid_matrix_id(" @dess:matrix.org"));
-    assert!(!is_valid_matrix_id("@dess:matrix.org t"));
+    assert!(is_valid_matrix_id("@dess:matrix.org").is_ok());
+    assert!(is_valid_matrix_id("dess:matrix.org").is_err());
+    assert!(is_valid_matrix_id(" @dess:matrix.org").is_err());
+    assert!(is_valid_matrix_id("@dess:matrix.org t").is_err());
   }
 
   #[test]