Disallow <code> tags in bio
This commit is contained in:
parent
448b5afa88
commit
0548e6e72a
5 changed files with 59 additions and 37 deletions
|
@ -3,3 +3,4 @@ pub mod helpers;
|
|||
pub mod mentions;
|
||||
pub mod queries;
|
||||
pub mod types;
|
||||
mod validators;
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql};
|
|||
use crate::errors::{ConversionError, DatabaseError, ValidationError};
|
||||
use crate::models::attachments::types::DbMediaAttachment;
|
||||
use crate::models::profiles::types::DbActorProfile;
|
||||
use crate::utils::html::clean_html_strict;
|
||||
use super::validators::clean_content;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Visibility {
|
||||
|
@ -263,15 +263,7 @@ impl PostCreateData {
|
|||
/// Validate and clean post data (only for local posts).
|
||||
pub fn clean(&mut self, character_limit: usize) -> Result<(), ValidationError> {
|
||||
assert!(self.object_id.is_none());
|
||||
if self.content.chars().count() > character_limit {
|
||||
return Err(ValidationError("post is too long"));
|
||||
};
|
||||
let content_safe = clean_html_strict(&self.content);
|
||||
let content_trimmed = content_safe.trim();
|
||||
if content_trimmed.is_empty() {
|
||||
return Err(ValidationError("post can not be empty"));
|
||||
};
|
||||
self.content = content_trimmed.to_string();
|
||||
self.content = clean_content(&self.content, character_limit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -288,16 +280,7 @@ mod tests {
|
|||
const POST_CHARACTER_LIMIT: usize = 1000;
|
||||
|
||||
#[test]
|
||||
fn test_post_data_empty() {
|
||||
let mut post_data_1 = PostCreateData {
|
||||
content: " ".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(post_data_1.clean(POST_CHARACTER_LIMIT).is_ok(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_post_data_trimming() {
|
||||
fn test_post_data_clean() {
|
||||
let mut post_data_2 = PostCreateData {
|
||||
content: "test ".to_string(),
|
||||
..Default::default()
|
||||
|
|
40
src/models/posts/validators.rs
Normal file
40
src/models/posts/validators.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use crate::errors::ValidationError;
|
||||
use crate::utils::html::clean_html_strict;
|
||||
|
||||
const CONTENT_ALLOWED_TAGS: [&str; 4] = ["a", "br", "pre", "code"];
|
||||
|
||||
pub fn clean_content(
|
||||
content: &str,
|
||||
character_limit: usize,
|
||||
) -> Result<String, ValidationError> {
|
||||
if content.chars().count() > character_limit {
|
||||
return Err(ValidationError("post is too long"));
|
||||
};
|
||||
let content_safe = clean_html_strict(content, &CONTENT_ALLOWED_TAGS);
|
||||
let content_trimmed = content_safe.trim();
|
||||
if content_trimmed.is_empty() {
|
||||
return Err(ValidationError("post can not be empty"));
|
||||
};
|
||||
Ok(content_trimmed.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const POST_CHARACTER_LIMIT: usize = 1000;
|
||||
|
||||
#[test]
|
||||
fn test_clean_content_empty() {
|
||||
let content = " ";
|
||||
let result = clean_content(content, POST_CHARACTER_LIMIT);
|
||||
assert_eq!(result.is_ok(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean_content_trimming() {
|
||||
let content = "test ";
|
||||
let cleaned = clean_content(content, POST_CHARACTER_LIMIT).unwrap();
|
||||
assert_eq!(cleaned, "test");
|
||||
}
|
||||
}
|
|
@ -4,6 +4,11 @@ use crate::utils::html::{clean_html, clean_html_strict};
|
|||
use super::types::ExtraField;
|
||||
|
||||
const USERNAME_RE: &str = r"^[a-zA-Z0-9_\.-]+$";
|
||||
const DISPLAY_NAME_MAX_LENGTH: usize = 200;
|
||||
const BIO_MAX_LENGTH: usize = 10000;
|
||||
const BIO_ALLOWED_TAGS: [&str; 2] = ["a", "br"];
|
||||
const FIELD_NAME_MAX_SIZE: usize = 500;
|
||||
const FIELD_VALUE_MAX_SIZE: usize = 5000;
|
||||
|
||||
pub fn validate_username(username: &str) -> Result<(), ValidationError> {
|
||||
if username.is_empty() {
|
||||
|
@ -19,8 +24,6 @@ pub fn validate_username(username: &str) -> Result<(), ValidationError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
const DISPLAY_NAME_MAX_LENGTH: usize = 200;
|
||||
|
||||
pub fn validate_display_name(display_name: &str)
|
||||
-> Result<(), ValidationError>
|
||||
{
|
||||
|
@ -30,8 +33,6 @@ pub fn validate_display_name(display_name: &str)
|
|||
Ok(())
|
||||
}
|
||||
|
||||
const BIO_MAX_LENGTH: usize = 10000;
|
||||
|
||||
pub fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError> {
|
||||
let cleaned_bio = if is_remote {
|
||||
// Remote profile
|
||||
|
@ -42,14 +43,11 @@ pub fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError>
|
|||
if bio.chars().count() > BIO_MAX_LENGTH {
|
||||
return Err(ValidationError("bio is too long"));
|
||||
};
|
||||
clean_html_strict(bio)
|
||||
clean_html_strict(bio, &BIO_ALLOWED_TAGS)
|
||||
};
|
||||
Ok(cleaned_bio)
|
||||
}
|
||||
|
||||
const FIELD_NAME_MAX_SIZE: usize = 500;
|
||||
const FIELD_VALUE_MAX_SIZE: usize = 5000;
|
||||
|
||||
/// Validates extra fields and removes fields with empty labels
|
||||
pub fn clean_extra_fields(extra_fields: &[ExtraField])
|
||||
-> Result<Vec<ExtraField>, ValidationError>
|
||||
|
@ -57,7 +55,7 @@ pub fn clean_extra_fields(extra_fields: &[ExtraField])
|
|||
let mut cleaned_extra_fields = vec![];
|
||||
for mut field in extra_fields.iter().cloned() {
|
||||
field.name = field.name.trim().to_string();
|
||||
field.value = clean_html_strict(&field.value);
|
||||
field.value = clean_html_strict(&field.value, &BIO_ALLOWED_TAGS);
|
||||
if field.name.is_empty() {
|
||||
continue;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::HashSet;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use ammonia::Builder;
|
||||
|
||||
|
@ -12,13 +13,12 @@ pub fn clean_html(unsafe_html: &str) -> String {
|
|||
safe_html
|
||||
}
|
||||
|
||||
pub fn clean_html_strict(unsafe_html: &str) -> String {
|
||||
let mut allowed_tags = HashSet::new();
|
||||
allowed_tags.insert("a");
|
||||
allowed_tags.insert("br");
|
||||
allowed_tags.insert("pre");
|
||||
allowed_tags.insert("code");
|
||||
|
||||
pub fn clean_html_strict(
|
||||
unsafe_html: &str,
|
||||
allowed_tags: &[&str],
|
||||
) -> String {
|
||||
let allowed_tags =
|
||||
HashSet::from_iter(allowed_tags.iter().copied());
|
||||
let safe_html = Builder::default()
|
||||
.tags(allowed_tags)
|
||||
.clean(unsafe_html)
|
||||
|
@ -47,7 +47,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_clean_html_strict() {
|
||||
let unsafe_html = r#"<p>test <b>bold</b><script>dangerous</script> with <a href="https://example.com">link</a> and <code>code</code></p>"#;
|
||||
let safe_html = clean_html_strict(unsafe_html);
|
||||
let safe_html = clean_html_strict(unsafe_html, &["a", "br", "code"]);
|
||||
assert_eq!(safe_html, r#"test bold with <a href="https://example.com" rel="noopener noreferrer">link</a> and <code>code</code>"#);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue