X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fapub%2Fsrc%2Fobjects%2Fpost.rs;h=f04e07ded3b9961ad39e36720133946dc3d89e9d;hb=3471f3533cb724b2cf6953d563aadfcc9f66c1d2;hp=b255ffb9b66efe93b7cd968a12b39fe1d486f395;hpb=2423b89ced5c2d110c1284777407682f748a068f;p=lemmy.git diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index b255ffb9..f04e07de 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -1,7 +1,7 @@ use crate::{ activities::{verify_is_public, verify_person_in_community}, check_apub_id_valid_with_strictness, - fetch_local_site_data, + local_site_data_cached, objects::{read_from_string_or_source_opt, verify_is_remote_object}, protocol::{ objects::{ @@ -25,7 +25,13 @@ use html2md::parse_html; use lemmy_api_common::{ context::LemmyContext, request::fetch_site_data, - utils::{is_mod_or_admin, local_site_opt_to_slur_regex}, + utils::{ + is_mod_or_admin, + local_site_opt_to_sensitive, + local_site_opt_to_slur_regex, + sanitize_html, + sanitize_html_opt, + }, }; use lemmy_db_schema::{ self, @@ -44,6 +50,7 @@ use lemmy_utils::{ markdown::markdown_to_html, slurs::{check_slurs_opt, remove_slurs}, time::convert_datetime, + validation::check_url_scheme, }, }; use std::ops::Deref; @@ -83,7 +90,7 @@ impl Object for ApubPost { context: &Data, ) -> Result, LemmyError> { Ok( - Post::read_from_apub_id(context.pool(), object_id) + Post::read_from_apub_id(&mut context.pool(), object_id) .await? .map(Into::into), ) @@ -93,7 +100,7 @@ impl Object for ApubPost { async fn delete(self, context: &Data) -> Result<(), LemmyError> { if !self.deleted { let form = PostUpdateForm::builder().deleted(Some(true)).build(); - Post::update(context.pool(), self.id, &form).await?; + Post::update(&mut context.pool(), self.id, &form).await?; } Ok(()) } @@ -102,10 +109,10 @@ impl Object for ApubPost { #[tracing::instrument(skip_all)] async fn into_json(self, context: &Data) -> Result { let creator_id = self.creator_id; - let creator = Person::read(context.pool(), creator_id).await?; + let creator = Person::read(&mut context.pool(), creator_id).await?; let community_id = self.community_id; - let community = Community::read(context.pool(), community_id).await?; - let language = LanguageTag::new_single(self.language_id, context.pool()).await?; + let community = Community::read(&mut context.pool(), community_id).await?; + let language = LanguageTag::new_single(self.language_id, &mut context.pool()).await?; let page = Page { kind: PageType::Page, @@ -143,17 +150,11 @@ impl Object for ApubPost { verify_is_remote_object(page.id.inner(), context.settings())?; }; - let local_site_data = fetch_local_site_data(context.pool()).await?; - let community = page.community(context).await?; - check_apub_id_valid_with_strictness( - page.id.inner(), - community.local, - &local_site_data, - context.settings(), - )?; + check_apub_id_valid_with_strictness(page.id.inner(), community.local, context).await?; verify_person_in_community(&page.creator()?, &community, context).await?; + let local_site_data = local_site_data_cached(&mut context.pool()).await?; let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site); check_slurs_opt(&page.name, slur_regex)?; @@ -167,7 +168,7 @@ impl Object for ApubPost { let creator = page.creator()?.dereference(context).await?; let community = page.community(context).await?; if community.posting_restricted_to_mods { - is_mod_or_admin(context.pool(), creator.id, community.id).await?; + is_mod_or_admin(&mut context.pool(), creator.id, community.id).await?; } let mut name = page .name @@ -197,24 +198,45 @@ impl Object for ApubPost { } else { None }; + check_url_scheme(&url)?; + + let local_site = LocalSite::read(&mut context.pool()).await.ok(); + let allow_sensitive = local_site_opt_to_sensitive(&local_site); + let page_is_sensitive = page.sensitive.unwrap_or(false); + let include_image = allow_sensitive || !page_is_sensitive; + // Only fetch metadata if the post has a url and was not seen previously. We dont want to // waste resources by fetching metadata for the same post multiple times. - let (metadata_res, thumbnail_url) = match &url { + // Additionally, only fetch image if content is not sensitive or is allowed on local site. + let (metadata_res, thumbnail) = match &url { Some(url) if old_post.is_err() => { - fetch_site_data(context.client(), context.settings(), Some(url)).await + fetch_site_data( + context.client(), + context.settings(), + Some(url), + include_image, + ) + .await } - _ => (None, page.image.map(|i| i.url.into())), + _ => (None, None), }; + // If no image was included with metadata, use post image instead when available. + let thumbnail_url = thumbnail.or_else(|| page.image.map(|i| i.url.into())); + let (embed_title, embed_description, embed_video_url) = metadata_res .map(|u| (u.title, u.description, u.embed_video_url)) .unwrap_or_default(); - let local_site = LocalSite::read(context.pool()).await.ok(); let slur_regex = &local_site_opt_to_slur_regex(&local_site); let body_slurs_removed = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source) .map(|s| remove_slurs(&s, slur_regex)); - let language_id = LanguageTag::to_language_id_single(page.language, context.pool()).await?; + let language_id = + LanguageTag::to_language_id_single(page.language, &mut context.pool()).await?; + + let name = sanitize_html(&name); + let embed_title = sanitize_html_opt(&embed_title); + let embed_description = sanitize_html_opt(&embed_description); PostInsertForm { name, @@ -250,7 +272,7 @@ impl Object for ApubPost { .build() }; - let post = Post::create(context.pool(), &form).await?; + let post = Post::create(&mut context.pool(), &form).await?; // write mod log entry for lock if Page::is_locked_changed(&old_post, &page.comments_enabled) { @@ -259,7 +281,7 @@ impl Object for ApubPost { post_id: post.id, locked: Some(post.locked), }; - ModLockPost::create(context.pool(), &form).await?; + ModLockPost::create(&mut context.pool(), &form).await?; } Ok(post.into()) @@ -268,6 +290,9 @@ impl Object for ApubPost { #[cfg(test)] mod tests { + #![allow(clippy::unwrap_used)] + #![allow(clippy::indexing_slicing)] + use super::*; use crate::{ objects::{ @@ -281,7 +306,7 @@ mod tests { use lemmy_db_schema::source::site::Site; use serial_test::serial; - #[actix_rt::test] + #[tokio::test] #[serial] async fn test_parse_lemmy_post() { let context = init_context().await; @@ -301,11 +326,13 @@ mod tests { assert!(!post.featured_community); assert_eq!(context.request_count(), 0); - Post::delete(context.pool(), post.id).await.unwrap(); - Person::delete(context.pool(), person.id).await.unwrap(); - Community::delete(context.pool(), community.id) + Post::delete(&mut context.pool(), post.id).await.unwrap(); + Person::delete(&mut context.pool(), person.id) + .await + .unwrap(); + Community::delete(&mut context.pool(), community.id) .await .unwrap(); - Site::delete(context.pool(), site.id).await.unwrap(); + Site::delete(&mut context.pool(), site.id).await.unwrap(); } }