Validate and clean bio when profile is created or updated

This commit is contained in:
silverpill 2022-02-17 00:03:27 +00:00
parent 4e010f1698
commit 82e24ad8b0
3 changed files with 47 additions and 17 deletions

View file

@ -57,7 +57,7 @@ pub async fn get_or_import_profile_by_actor_id(
let profile = match get_profile_by_actor_id(db_client, actor_id).await { let profile = match get_profile_by_actor_id(db_client, actor_id).await {
Ok(profile) => profile, Ok(profile) => profile,
Err(DatabaseError::NotFound(_)) => { Err(DatabaseError::NotFound(_)) => {
let profile_data = fetch_profile_by_actor_id( let mut profile_data = fetch_profile_by_actor_id(
instance, actor_id, media_dir, instance, actor_id, media_dir,
) )
.await .await
@ -85,7 +85,7 @@ pub async fn import_profile_by_actor_address(
if actor_address.instance == instance.host() { if actor_address.instance == instance.host() {
return Err(ImportError::LocalObject); return Err(ImportError::LocalObject);
}; };
let profile_data = fetch_profile( let mut profile_data = fetch_profile(
instance, instance,
&actor_address.username, &actor_address.username,
&actor_address.instance, &actor_address.instance,

View file

@ -15,6 +15,7 @@ use crate::utils::html::clean_html_strict;
use super::validators::{ use super::validators::{
validate_username, validate_username,
validate_display_name, validate_display_name,
clean_bio,
}; };
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
@ -153,9 +154,15 @@ pub struct ProfileCreateData {
} }
impl ProfileCreateData { impl ProfileCreateData {
pub fn clean(&self) -> Result<(), ValidationError> { pub fn clean(&mut self) -> Result<(), ValidationError> {
validate_username(&self.username)?; validate_username(&self.username)?;
validate_display_name(self.display_name.as_ref())?; if let Some(display_name) = &self.display_name {
validate_display_name(display_name)?;
};
if let Some(bio) = &self.bio {
let cleaned_bio = clean_bio(bio, self.actor_json.is_some())?;
self.bio = Some(cleaned_bio);
};
Ok(()) Ok(())
} }
} }
@ -172,8 +179,14 @@ pub struct ProfileUpdateData {
impl ProfileUpdateData { impl ProfileUpdateData {
pub fn clean(&mut self) -> Result<(), ValidationError> { pub fn clean(&mut self) -> Result<(), ValidationError> {
if let Some(display_name) = &self.display_name {
validate_display_name(display_name)?;
};
// Validate and clean bio // Validate and clean bio
self.bio = self.bio.as_ref().map(|val| clean_html_strict(val)); if let Some(bio) = &self.bio {
let cleaned_bio = clean_bio(bio, self.actor_json.is_some())?;
self.bio = Some(cleaned_bio);
};
// Clean extra fields and remove fields with empty labels // Clean extra fields and remove fields with empty labels
self.extra_fields = self.extra_fields.iter().cloned() self.extra_fields = self.extra_fields.iter().cloned()
.map(|mut field| { .map(|mut field| {

View file

@ -1,4 +1,5 @@
use crate::errors::ValidationError; use crate::errors::ValidationError;
use crate::utils::html::{clean_html, clean_html_strict};
pub fn validate_username(username: &str) -> Result<(), ValidationError> { pub fn validate_username(username: &str) -> Result<(), ValidationError> {
if username.len() > 100 { if username.len() > 100 {
@ -7,17 +8,31 @@ pub fn validate_username(username: &str) -> Result<(), ValidationError> {
Ok(()) Ok(())
} }
pub fn validate_display_name(display_name: Option<&String>) pub fn validate_display_name(display_name: &str)
-> Result<(), ValidationError> -> Result<(), ValidationError>
{ {
if let Some(display_name) = display_name { if display_name.len() > 200 {
if display_name.len() > 200 { return Err(ValidationError("display name is too long"));
return Err(ValidationError("display name is too long"));
};
}; };
Ok(()) Ok(())
} }
const BIO_MAX_SIZE: usize = 10000;
pub fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError> {
if bio.len() > BIO_MAX_SIZE {
return Err(ValidationError("bio is too long"));
};
let cleaned_bio = if is_remote {
// Remote profile
clean_html(bio)
} else {
// Local profile
clean_html_strict(bio)
};
Ok(cleaned_bio)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -32,15 +47,17 @@ mod tests {
#[test] #[test]
fn test_validate_display_name() { fn test_validate_display_name() {
let display_name = "test".to_string(); let result_1 = validate_display_name("test");
let result_1 = validate_display_name(Some(&display_name));
assert!(result_1.is_ok()); assert!(result_1.is_ok());
let result_2 = validate_display_name(None); let result_2 = validate_display_name(&"x".repeat(201));
assert!(result_2.is_ok()); assert!(result_2.is_err());
}
let display_name = "x".repeat(201); #[test]
let result_3 = validate_display_name(Some(&display_name)); fn test_clean_bio() {
assert!(result_3.is_err()); let bio = "test\n<script>alert()</script>123";
let result = clean_bio(bio, true).unwrap();
assert_eq!(result, "test\n123");
} }
} }