Merge pull request 'Enforce post lock in federation inbox' (#129) from enforce-post-lock into main

Reviewed-on: https://yerbamate.ml/LemmyNet/lemmy/pulls/129
This commit is contained in:
dessalines 2020-11-10 13:16:13 +00:00
commit 94dd335fac
8 changed files with 49 additions and 19 deletions

View file

@ -175,7 +175,7 @@ impl Perform for Register {
published: None, published: None,
updated: None, updated: None,
admin: data.admin, admin: data.admin,
banned: false, banned: Some(false),
show_nsfw: data.show_nsfw, show_nsfw: data.show_nsfw,
theme: "browser".into(), theme: "browser".into(),
default_sort_type: SortType::Active as i16, default_sort_type: SortType::Active as i16,
@ -407,7 +407,7 @@ impl Perform for SaveUserSettings {
published: Some(read_user.published), published: Some(read_user.published),
updated: Some(naive_now()), updated: Some(naive_now()),
admin: read_user.admin, admin: read_user.admin,
banned: read_user.banned, banned: Some(read_user.banned),
show_nsfw: data.show_nsfw, show_nsfw: data.show_nsfw,
theme: data.theme.to_owned(), theme: data.theme.to_owned(),
default_sort_type: data.default_sort_type, default_sort_type: data.default_sort_type,

View file

@ -9,7 +9,7 @@ use activitystreams::{
base::ExtendsExt, base::ExtendsExt,
object::Note, object::Note,
}; };
use anyhow::Context; use anyhow::{anyhow, Context};
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView, comment_view::CommentView,
@ -33,12 +33,15 @@ pub(crate) async fn receive_create_comment(
let comment = let comment =
CommentForm::from_apub(&note, context, Some(user.actor_id()?), request_counter).await?; CommentForm::from_apub(&note, 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 = let inserted_comment =
blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??; 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: // Note:
// Although mentions could be gotten from the post tags (they are included there), or the ccs, // 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 // Its much easier to scrape them from the comment body, since the API has to do that

View file

@ -497,6 +497,12 @@ pub(crate) async fn get_or_fetch_and_insert_comment(
) )
.await?; .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| { let comment = blocking(context.pool(), move |conn| {
Comment::upsert(conn, &comment_form) Comment::upsert(conn, &comment_form)
}) })

View file

@ -27,7 +27,9 @@ use actix_web::{web, HttpRequest, HttpResponse};
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use lemmy_db::{ use lemmy_db::{
community::{Community, CommunityFollower, CommunityFollowerForm}, community::{Community, CommunityFollower, CommunityFollowerForm},
community_view::CommunityUserBanView,
user::User_, user::User_,
DbPool,
Followable, Followable,
}; };
use lemmy_structs::blocking; use lemmy_structs::blocking;
@ -110,14 +112,21 @@ pub(crate) async fn community_receive_message(
context: &LemmyContext, context: &LemmyContext,
request_counter: &mut i32, request_counter: &mut i32,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
// 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 any_base = activity.clone().into_any_base()?;
let actor_url = actor.actor_id()?; let actor_url = actor.actor_id()?;
let activity_kind = activity.kind().context(location_info!())?; let activity_kind = activity.kind().context(location_info!())?;
let do_announce = match activity_kind { let do_announce = match activity_kind {
CommunityValidTypes::Follow => { CommunityValidTypes::Follow => {
handle_follow(any_base.clone(), actor_url, &to_community, &context).await?; handle_follow(any_base.clone(), user, &to_community, &context).await?;
false false
} }
CommunityValidTypes::Undo => { CommunityValidTypes::Undo => {
@ -172,17 +181,13 @@ pub(crate) async fn community_receive_message(
/// Accept activity. /// Accept activity.
async fn handle_follow( async fn handle_follow(
activity: AnyBase, activity: AnyBase,
user_url: Url, user: User_,
community: &Community, community: &Community,
context: &LemmyContext, context: &LemmyContext,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let follow = Follow::from_any_base(activity)?.context(location_info!())?; 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 { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,
user_id: user.id, user_id: user.id,
@ -250,3 +255,21 @@ async fn handle_undo_follow(
Ok(()) 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(())
}

View file

@ -135,7 +135,6 @@ pub(in crate::inbox) async fn receive_delete_for_community(
activity: AnyBase, activity: AnyBase,
expected_domain: &Url, expected_domain: &Url,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
dbg!("receive_delete_for_community");
let delete = Delete::from_any_base(activity)?.context(location_info!())?; let delete = Delete::from_any_base(activity)?.context(location_info!())?;
verify_activity_domains_valid(&delete, &expected_domain, true)?; verify_activity_domains_valid(&delete, &expected_domain, true)?;
is_addressed_to_public(&delete)?; is_addressed_to_public(&delete)?;
@ -160,7 +159,6 @@ pub(in crate::inbox) async fn receive_remove_for_community(
activity: AnyBase, activity: AnyBase,
expected_domain: &Url, expected_domain: &Url,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
dbg!("receive_remove_for_community");
let remove = Remove::from_any_base(activity)?.context(location_info!())?; let remove = Remove::from_any_base(activity)?.context(location_info!())?;
verify_activity_domains_valid(&remove, &expected_domain, false)?; verify_activity_domains_valid(&remove, &expected_domain, false)?;
is_addressed_to_public(&remove)?; is_addressed_to_public(&remove)?;

View file

@ -132,7 +132,7 @@ impl FromApub for UserForm {
preferred_username: Some(preferred_username), preferred_username: Some(preferred_username),
password_encrypted: "".to_string(), password_encrypted: "".to_string(),
admin: false, admin: false,
banned: false, banned: None,
email: None, email: None,
avatar, avatar,
banner, banner,

View file

@ -46,7 +46,7 @@ pub struct UserForm {
pub preferred_username: Option<Option<String>>, pub preferred_username: Option<Option<String>>,
pub password_encrypted: String, pub password_encrypted: String,
pub admin: bool, pub admin: bool,
pub banned: bool, pub banned: Option<bool>,
pub email: Option<Option<String>>, pub email: Option<Option<String>>,
pub avatar: Option<Option<String>>, pub avatar: Option<Option<String>>,
pub published: Option<chrono::NaiveDateTime>, pub published: Option<chrono::NaiveDateTime>,

View file

@ -57,7 +57,7 @@ fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
published: Some(cuser.published), published: Some(cuser.published),
updated: None, updated: None,
admin: cuser.admin, admin: cuser.admin,
banned: cuser.banned, banned: Some(cuser.banned),
show_nsfw: cuser.show_nsfw, show_nsfw: cuser.show_nsfw,
theme: cuser.theme.to_owned(), theme: cuser.theme.to_owned(),
default_sort_type: cuser.default_sort_type, default_sort_type: cuser.default_sort_type,