From 2402515fccee0c6ee79ed8e1fecf6b0449efa2c4 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 14 Oct 2021 12:33:19 -0400 Subject: [PATCH] Dont allow posts to deleted / removed communities. Fixes #1827 (#1828) * Dont allow posts to deleted / removed communities. Fixes #1827 * Fixing couldnt find community error. * Adding check in createorupdate post and comment. * make sure post wasn't deleted or removed. * Adding a post not deleted or removed check to creatorupdatecomment. * Using pub(crate) --- api_tests/src/post.spec.ts | 2 +- crates/api/src/community.rs | 2 ++ crates/api/src/post.rs | 4 ++++ crates/api_common/src/lib.rs | 22 +++++++++++++++++++ crates/api_crud/src/comment/create.rs | 4 ++++ crates/api_crud/src/comment/update.rs | 4 ++++ crates/api_crud/src/post/create.rs | 2 ++ crates/api_crud/src/post/delete.rs | 2 ++ crates/api_crud/src/post/update.rs | 9 +++++++- .../activities/comment/create_or_update.rs | 7 +++++- crates/apub/src/activities/mod.rs | 8 +++++++ .../src/activities/post/create_or_update.rs | 3 +++ crates/apub/src/objects/comment.rs | 2 +- 13 files changed, 67 insertions(+), 4 deletions(-) diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 507262047..280396b00 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -90,7 +90,7 @@ test('Create a post', async () => { test('Create a post in a non-existent community', async () => { let postRes = await createPost(alpha, -2); - expect(postRes).toStrictEqual({ error: 'couldnt_create_post' }); + expect(postRes).toStrictEqual({ error: 'couldnt_find_community' }); }); test('Unlike a post', async () => { diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index 7a5e622ca..ccf0edbfd 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -4,6 +4,7 @@ use anyhow::Context; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, community::*, get_local_user_view_from_jwt, is_mod_or_admin, @@ -70,6 +71,7 @@ impl Perform for FollowCommunity { if community.local { if data.follow { check_community_ban(local_user_view.person.id, community_id, context.pool()).await?; + check_community_deleted_or_removed(community_id, context.pool()).await?; let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); blocking(context.pool(), follow) diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index d2440b7a3..a79a4bb5e 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -3,6 +3,7 @@ use actix_web::web::Data; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, check_downvotes_enabled, check_person_block, get_local_user_view_from_jwt, @@ -49,6 +50,7 @@ impl Perform for CreatePostLike { let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?; + check_community_deleted_or_removed(post.community_id, context.pool()).await?; check_person_block(local_user_view.person.id, post.creator_id, context.pool()).await?; @@ -133,6 +135,7 @@ impl Perform for LockPost { context.pool(), ) .await?; + check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?; // Verify that only the mods can lock is_mod_or_admin( @@ -200,6 +203,7 @@ impl Perform for StickyPost { context.pool(), ) .await?; + check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?; // Verify that only the mods can sticky is_mod_or_admin( diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index 07edab0f7..c4b1dd6f5 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -357,6 +357,28 @@ pub async fn check_community_ban( } } +pub async fn check_community_deleted_or_removed( + community_id: CommunityId, + pool: &DbPool, +) -> Result<(), LemmyError> { + let community = blocking(pool, move |conn| Community::read(conn, community_id)) + .await? + .map_err(|e| ApiError::err("couldnt_find_community", e))?; + if community.deleted || community.removed { + Err(ApiError::err_plain("deleted").into()) + } else { + Ok(()) + } +} + +pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { + if post.deleted || post.removed { + Err(ApiError::err_plain("deleted").into()) + } else { + Ok(()) + } +} + pub async fn check_person_block( my_id: PersonId, potential_blocker_id: PersonId, diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 674914629..37ecb2f05 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -3,7 +3,9 @@ use actix_web::web::Data; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, check_person_block, + check_post_deleted_or_removed, comment::*, get_local_user_view_from_jwt, get_post, @@ -56,6 +58,8 @@ impl PerformCrud for CreateComment { let community_id = post.community_id; check_community_ban(local_user_view.person.id, community_id, context.pool()).await?; + check_community_deleted_or_removed(community_id, context.pool()).await?; + check_post_deleted_or_removed(&post)?; check_person_block(local_user_view.person.id, post.creator_id, context.pool()).await?; diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 800e124d5..b0892c58c 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -3,6 +3,8 @@ use actix_web::web::Data; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, + check_post_deleted_or_removed, comment::*, get_local_user_view_from_jwt, send_local_notifs, @@ -48,6 +50,8 @@ impl PerformCrud for EditComment { context.pool(), ) .await?; + check_community_deleted_or_removed(orig_comment.community.id, context.pool()).await?; + check_post_deleted_or_removed(&orig_comment.post)?; // Verify that only the creator can edit if local_user_view.person.id != orig_comment.creator.id { diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 89e664631..108205b7c 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -3,6 +3,7 @@ use actix_web::web::Data; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, get_local_user_view_from_jwt, honeypot_check, mark_post_as_read, @@ -54,6 +55,7 @@ impl PerformCrud for CreatePost { } 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?; // Fetch post links and pictrs cached image let data_url = data.url.as_ref(); diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index f4086f39d..01fa0575b 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -3,6 +3,7 @@ use actix_web::web::Data; use lemmy_api_common::{ blocking, check_community_ban, + check_community_deleted_or_removed, get_local_user_view_from_jwt, is_mod_or_admin, post::*, @@ -35,6 +36,7 @@ impl PerformCrud for DeletePost { context.pool(), ) .await?; + check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?; // Verify that only the creator can delete if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 9ccb2c052..c84901cc8 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -1,6 +1,12 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{blocking, check_community_ban, get_local_user_view_from_jwt, post::*}; +use lemmy_api_common::{ + blocking, + check_community_ban, + check_community_deleted_or_removed, + get_local_user_view_from_jwt, + post::*, +}; use lemmy_apub::activities::{post::create_or_update::CreateOrUpdatePost, CreateOrUpdateType}; use lemmy_db_queries::{source::post::Post_, Crud}; use lemmy_db_schema::{naive_now, source::post::*}; @@ -45,6 +51,7 @@ impl PerformCrud for EditPost { context.pool(), ) .await?; + check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?; // Verify that only the creator can edit if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { diff --git a/crates/apub/src/activities/comment/create_or_update.rs b/crates/apub/src/activities/comment/create_or_update.rs index c225300f3..b22c240e6 100644 --- a/crates/apub/src/activities/comment/create_or_update.rs +++ b/crates/apub/src/activities/comment/create_or_update.rs @@ -1,5 +1,6 @@ use crate::{ activities::{ + check_community_deleted_or_removed, comment::{collect_non_local_mentions, get_notif_recipients}, community::{announce::AnnouncableActivities, send_to_community}, extract_community, @@ -13,7 +14,7 @@ use crate::{ objects::{comment::Note, FromApub, ToApub}, }; use activitystreams::{base::AnyBase, link::Mention, primitives::OneOrMany, unparsed::Unparsed}; -use lemmy_api_common::blocking; +use lemmy_api_common::{blocking, check_post_deleted_or_removed}; use lemmy_apub_lib::{ data::Data, traits::{ActivityFields, ActivityHandler, ActorType}, @@ -94,10 +95,14 @@ impl ActivityHandler for CreateOrUpdateComment { ) -> Result<(), LemmyError> { let community = extract_community(&self.cc, context, request_counter).await?; let community_id = ObjectId::new(community.actor_id()); + let post = self.object.get_parents(context, request_counter).await?.0; verify_activity(self, &context.settings())?; verify_person_in_community(&self.actor, &community_id, context, request_counter).await?; verify_domains_match(self.actor.inner(), self.object.id_unchecked())?; + check_community_deleted_or_removed(&community)?; + check_post_deleted_or_removed(&post)?; + // TODO: should add a check that the correct community is in cc (probably needs changes to // comment deserialization) self.object.verify(context, request_counter).await?; diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 5c775f801..43f86572f 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -133,6 +133,14 @@ fn verify_add_remove_moderator_target( Ok(()) } +pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> { + if community.deleted || community.removed { + Err(anyhow!("New post or comment cannot be created in deleted or removed community").into()) + } else { + Ok(()) + } +} + /// Generate a unique ID for an activity, in the format: /// `http(s)://example.com/receive/create/202daf0a-1489-45df-8d2e-c8a3173fed36` fn generate_activity_id(kind: T, protocol_and_hostname: &str) -> Result diff --git a/crates/apub/src/activities/post/create_or_update.rs b/crates/apub/src/activities/post/create_or_update.rs index 8065cc879..f1a336680 100644 --- a/crates/apub/src/activities/post/create_or_update.rs +++ b/crates/apub/src/activities/post/create_or_update.rs @@ -1,5 +1,6 @@ use crate::{ activities::{ + check_community_deleted_or_removed, community::{announce::AnnouncableActivities, send_to_community}, generate_activity_id, verify_activity, @@ -87,6 +88,8 @@ impl ActivityHandler for CreateOrUpdatePost { verify_activity(self, &context.settings())?; let community = self.cc[0].dereference(context, request_counter).await?; verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?; + check_community_deleted_or_removed(&community)?; + match self.kind { CreateOrUpdateType::Create => { verify_domains_match(self.actor.inner(), self.object.id_unchecked())?; diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 1e01b3f56..f47c11bfb 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -73,7 +73,7 @@ impl Note { Ok(&self.id) } - async fn get_parents( + pub(crate) async fn get_parents( &self, context: &LemmyContext, request_counter: &mut i32,