From 8803e7834fc145418fed62e592258f18303c2e2e Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 9 Nov 2020 15:29:36 +0100 Subject: [PATCH 1/2] Enforce site and community bans for federated users --- lemmy_api/src/user.rs | 4 +- lemmy_apub/src/inbox/community_inbox.rs | 39 +++++++++++++++---- lemmy_apub/src/inbox/receive_for_community.rs | 2 - lemmy_apub/src/objects/user.rs | 2 +- lemmy_db/src/user.rs | 2 +- src/code_migrations.rs | 2 +- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/lemmy_api/src/user.rs b/lemmy_api/src/user.rs index 6dffc1a79..41f77271a 100644 --- a/lemmy_api/src/user.rs +++ b/lemmy_api/src/user.rs @@ -175,7 +175,7 @@ impl Perform for Register { published: None, updated: None, admin: data.admin, - banned: false, + banned: Some(false), show_nsfw: data.show_nsfw, theme: "browser".into(), default_sort_type: SortType::Active as i16, @@ -407,7 +407,7 @@ impl Perform for SaveUserSettings { published: Some(read_user.published), updated: Some(naive_now()), admin: read_user.admin, - banned: read_user.banned, + banned: Some(read_user.banned), show_nsfw: data.show_nsfw, theme: data.theme.to_owned(), default_sort_type: data.default_sort_type, diff --git a/lemmy_apub/src/inbox/community_inbox.rs b/lemmy_apub/src/inbox/community_inbox.rs index 630a2db92..6cd4a017f 100644 --- a/lemmy_apub/src/inbox/community_inbox.rs +++ b/lemmy_apub/src/inbox/community_inbox.rs @@ -27,7 +27,9 @@ use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::{anyhow, Context}; use lemmy_db::{ community::{Community, CommunityFollower, CommunityFollowerForm}, + community_view::CommunityUserBanView, user::User_, + DbPool, Followable, }; use lemmy_structs::blocking; @@ -110,14 +112,21 @@ pub(crate) async fn community_receive_message( context: &LemmyContext, request_counter: &mut i32, ) -> Result { - // TODO: check if the sending user is banned by the community + // Only users can send activities to the community, so we can get the actor as user + // unconditionally. + let actor_id = actor.actor_id_str(); + let user = blocking(&context.pool(), move |conn| { + User_::read_from_actor_id(&conn, &actor_id) + }) + .await??; + check_community_or_site_ban(&user, &to_community, context.pool()).await?; let any_base = activity.clone().into_any_base()?; let actor_url = actor.actor_id()?; let activity_kind = activity.kind().context(location_info!())?; let do_announce = match activity_kind { CommunityValidTypes::Follow => { - handle_follow(any_base.clone(), actor_url, &to_community, &context).await?; + handle_follow(any_base.clone(), user, &to_community, &context).await?; false } CommunityValidTypes::Undo => { @@ -172,17 +181,13 @@ pub(crate) async fn community_receive_message( /// Accept activity. async fn handle_follow( activity: AnyBase, - user_url: Url, + user: User_, community: &Community, context: &LemmyContext, ) -> Result { let follow = Follow::from_any_base(activity)?.context(location_info!())?; - verify_activity_domains_valid(&follow, &user_url, false)?; + verify_activity_domains_valid(&follow, &user.actor_id()?, false)?; - let user = blocking(&context.pool(), move |conn| { - User_::read_from_actor_id(&conn, user_url.as_str()) - }) - .await??; let community_follower_form = CommunityFollowerForm { community_id: community.id, user_id: user.id, @@ -250,3 +255,21 @@ async fn handle_undo_follow( Ok(()) } + +async fn check_community_or_site_ban( + user: &User_, + community: &Community, + pool: &DbPool, +) -> Result<(), LemmyError> { + if user.banned { + return Err(anyhow!("User is banned from site").into()); + } + let user_id = user.id; + let community_id = community.id; + let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok(); + if blocking(pool, is_banned).await? { + return Err(anyhow!("User is banned from community").into()); + } + + Ok(()) +} diff --git a/lemmy_apub/src/inbox/receive_for_community.rs b/lemmy_apub/src/inbox/receive_for_community.rs index d4cd43d77..b6dfa1e42 100644 --- a/lemmy_apub/src/inbox/receive_for_community.rs +++ b/lemmy_apub/src/inbox/receive_for_community.rs @@ -135,7 +135,6 @@ pub(in crate::inbox) async fn receive_delete_for_community( activity: AnyBase, expected_domain: &Url, ) -> Result<(), LemmyError> { - dbg!("receive_delete_for_community"); let delete = Delete::from_any_base(activity)?.context(location_info!())?; verify_activity_domains_valid(&delete, &expected_domain, true)?; is_addressed_to_public(&delete)?; @@ -160,7 +159,6 @@ pub(in crate::inbox) async fn receive_remove_for_community( activity: AnyBase, expected_domain: &Url, ) -> Result<(), LemmyError> { - dbg!("receive_remove_for_community"); let remove = Remove::from_any_base(activity)?.context(location_info!())?; verify_activity_domains_valid(&remove, &expected_domain, false)?; is_addressed_to_public(&remove)?; diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index 5ef1ec8e9..3c41b5584 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -132,7 +132,7 @@ impl FromApub for UserForm { preferred_username: Some(preferred_username), password_encrypted: "".to_string(), admin: false, - banned: false, + banned: None, email: None, avatar, banner, diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index db8a999eb..8dc613bb3 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -46,7 +46,7 @@ pub struct UserForm { pub preferred_username: Option>, pub password_encrypted: String, pub admin: bool, - pub banned: bool, + pub banned: Option, pub email: Option>, pub avatar: Option>, pub published: Option, diff --git a/src/code_migrations.rs b/src/code_migrations.rs index adc4ae49a..c41f5bd96 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -57,7 +57,7 @@ fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> { published: Some(cuser.published), updated: None, admin: cuser.admin, - banned: cuser.banned, + banned: Some(cuser.banned), show_nsfw: cuser.show_nsfw, theme: cuser.theme.to_owned(), default_sort_type: cuser.default_sort_type, From 3b4c3ec07478f994ef810a315edf6e122b0accda Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 9 Nov 2020 17:06:54 +0100 Subject: [PATCH 2/2] Enforce post lock in federation inbox --- lemmy_apub/src/activities/receive/comment.rs | 11 +++++++---- lemmy_apub/src/fetcher.rs | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index b60d4c950..d104d5e19 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -9,7 +9,7 @@ use activitystreams::{ base::ExtendsExt, object::Note, }; -use anyhow::Context; +use anyhow::{anyhow, Context}; use lemmy_db::{ comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, comment_view::CommentView, @@ -33,12 +33,15 @@ pub(crate) async fn receive_create_comment( let comment = CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let post_id = comment.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + if post.locked { + return Err(anyhow!("Post is locked").into()); + } + let inserted_comment = blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??; - let post_id = inserted_comment.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - // Note: // Although mentions could be gotten from the post tags (they are included there), or the ccs, // Its much easier to scrape them from the comment body, since the API has to do that diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index ff3b03d34..acf94ec9e 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -497,6 +497,12 @@ pub(crate) async fn get_or_fetch_and_insert_comment( ) .await?; + let post_id = comment_form.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + if post.locked { + return Err(anyhow!("Post is locked").into()); + } + let comment = blocking(context.pool(), move |conn| { Comment::upsert(conn, &comment_form) })