Move profile data cleaning code to validators::profiles module

This commit is contained in:
silverpill 2023-03-23 18:02:24 +00:00
parent 441850dd21
commit ef852d781e
4 changed files with 73 additions and 65 deletions

View file

@ -21,7 +21,10 @@ use crate::models::{
ProfileUpdateData,
},
};
use crate::validators::posts::EMOJIS_MAX_NUM;
use crate::validators::{
posts::EMOJIS_MAX_NUM,
profiles::{clean_profile_create_data, clean_profile_update_data},
};
pub const ACTOR_IMAGE_MAX_SIZE: usize = 5 * 1000 * 1000; // 5 MB
@ -173,7 +176,7 @@ pub async fn create_remote_profile(
emojis,
actor_json: Some(actor),
};
profile_data.clean()?;
clean_profile_create_data(&mut profile_data)?;
let profile = create_profile(db_client, profile_data).await?;
Ok(profile)
}
@ -231,7 +234,7 @@ pub async fn update_remote_profile(
emojis,
actor_json: Some(actor),
};
profile_data.clean()?;
clean_profile_update_data(&mut profile_data)?;
let profile = update_profile(db_client, &profile.id, profile_data).await?;
Ok(profile)
}

View file

@ -99,6 +99,7 @@ use crate::models::{
},
users::types::{Role, UserCreateData},
};
use crate::validators::profiles::clean_profile_update_data;
use super::helpers::{follow_or_create_request, get_relationship};
use super::types::{
Account,
@ -246,7 +247,7 @@ async fn update_credentials(
&current_user.profile,
&config.media_dir(),
)?;
profile_data.clean()?;
clean_profile_update_data(&mut profile_data)?;
current_user.profile = update_profile(
db_client,
&current_user.id,

View file

@ -20,14 +20,7 @@ use crate::database::{
json_macro::{json_from_sql, json_to_sql},
DatabaseTypeError,
};
use crate::errors::ValidationError;
use crate::models::emojis::types::DbEmoji;
use crate::validators::profiles::{
validate_username,
validate_display_name,
clean_bio,
clean_extra_fields,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ProfileImage {
@ -456,25 +449,6 @@ pub struct ProfileCreateData {
pub actor_json: Option<Actor>,
}
impl ProfileCreateData {
pub fn clean(&mut self) -> Result<(), ValidationError> {
validate_username(&self.username)?;
if self.hostname.is_some() != self.actor_json.is_some() {
return Err(ValidationError("hostname and actor_json field mismatch"));
};
if let Some(display_name) = &self.display_name {
validate_display_name(display_name)?;
};
let is_remote = self.actor_json.is_some();
if let Some(bio) = &self.bio {
let cleaned_bio = clean_bio(bio, is_remote)?;
self.bio = Some(cleaned_bio);
};
self.extra_fields = clean_extra_fields(&self.extra_fields, is_remote)?;
Ok(())
}
}
pub struct ProfileUpdateData {
pub display_name: Option<String>,
pub bio: Option<String>,
@ -506,20 +480,6 @@ impl ProfileUpdateData {
});
self.payment_options.push(option);
}
pub fn clean(&mut self) -> Result<(), ValidationError> {
if let Some(display_name) = &self.display_name {
validate_display_name(display_name)?;
};
let is_remote = self.actor_json.is_some();
// Validate and clean bio
if let Some(bio) = &self.bio {
let cleaned_bio = clean_bio(bio, is_remote)?;
self.bio = Some(cleaned_bio);
};
self.extra_fields = clean_extra_fields(&self.extra_fields, is_remote)?;
Ok(())
}
}
impl From<&DbActorProfile> for ProfileUpdateData {
@ -546,7 +506,6 @@ impl From<&DbActorProfile> for ProfileUpdateData {
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use super::*;
#[test]
@ -588,20 +547,4 @@ mod tests {
let serialized = serde_json::to_string(&payment_option).unwrap();
assert_eq!(serialized, r#"{"payment_type":2,"chain_id":"eip155:1"}"#);
}
#[test]
fn test_clean_profile_create_data() {
let mut profile_data = ProfileCreateData {
username: "test".to_string(),
hostname: Some("example.org".to_string()),
display_name: Some("Test Test".to_string()),
actor_json: Some(Actor {
id: "https://example.org/test".to_string(),
..Default::default()
}),
..Default::default()
};
let result = profile_data.clean();
assert_eq!(result.is_ok(), true);
}
}

View file

@ -3,7 +3,11 @@ use regex::Regex;
use mitra_utils::html::{clean_html, clean_html_strict};
use crate::errors::ValidationError;
use crate::models::profiles::types::ExtraField;
use crate::models::profiles::types::{
ExtraField,
ProfileCreateData,
ProfileUpdateData,
};
const USERNAME_RE: &str = r"^[a-zA-Z0-9_\.-]+$";
const DISPLAY_NAME_MAX_LENGTH: usize = 200;
@ -26,7 +30,7 @@ pub fn validate_username(username: &str) -> Result<(), ValidationError> {
Ok(())
}
pub fn validate_display_name(display_name: &str)
fn validate_display_name(display_name: &str)
-> Result<(), ValidationError>
{
if display_name.chars().count() > DISPLAY_NAME_MAX_LENGTH {
@ -35,7 +39,7 @@ pub fn validate_display_name(display_name: &str)
Ok(())
}
pub fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError> {
fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError> {
let cleaned_bio = if is_remote {
// Remote profile
let truncated_bio: String = bio.chars().take(BIO_MAX_LENGTH).collect();
@ -51,7 +55,7 @@ pub fn clean_bio(bio: &str, is_remote: bool) -> Result<String, ValidationError>
}
/// Validates extra fields and removes fields with empty labels
pub fn clean_extra_fields(
fn clean_extra_fields(
extra_fields: &[ExtraField],
is_remote: bool,
) -> Result<Vec<ExtraField>, ValidationError> {
@ -83,8 +87,49 @@ pub fn clean_extra_fields(
Ok(cleaned_extra_fields)
}
pub fn clean_profile_create_data(
profile_data: &mut ProfileCreateData,
) -> Result<(), ValidationError> {
validate_username(&profile_data.username)?;
if profile_data.hostname.is_some() != profile_data.actor_json.is_some() {
return Err(ValidationError("hostname and actor_json field mismatch"));
};
if let Some(display_name) = &profile_data.display_name {
validate_display_name(display_name)?;
};
let is_remote = profile_data.actor_json.is_some();
if let Some(bio) = &profile_data.bio {
let cleaned_bio = clean_bio(bio, is_remote)?;
profile_data.bio = Some(cleaned_bio);
};
profile_data.extra_fields = clean_extra_fields(
&profile_data.extra_fields,
is_remote,
)?;
Ok(())
}
pub fn clean_profile_update_data(
profile_data: &mut ProfileUpdateData,
) -> Result<(), ValidationError> {
if let Some(display_name) = &profile_data.display_name {
validate_display_name(display_name)?;
};
let is_remote = profile_data.actor_json.is_some();
if let Some(bio) = &profile_data.bio {
let cleaned_bio = clean_bio(bio, is_remote)?;
profile_data.bio = Some(cleaned_bio);
};
profile_data.extra_fields = clean_extra_fields(
&profile_data.extra_fields,
is_remote,
)?;
Ok(())
}
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use super::*;
#[test]
@ -133,4 +178,20 @@ mod tests {
assert_eq!(result.name, "$ETH");
assert_eq!(result.value, "0x1234");
}
#[test]
fn test_clean_profile_create_data() {
let mut profile_data = ProfileCreateData {
username: "test".to_string(),
hostname: Some("example.org".to_string()),
display_name: Some("Test Test".to_string()),
actor_json: Some(Actor {
id: "https://example.org/test".to_string(),
..Default::default()
}),
..Default::default()
};
let result = clean_profile_create_data(&mut profile_data);
assert_eq!(result.is_ok(), true);
}
}