mirror of https://github.com/LemmyNet/lemmy.git
Add local community ban, and nonlocal person check.
parent
eba42de4bd
commit
0caaac193d
|
@ -2555,7 +2555,6 @@ dependencies = [
|
||||||
"captcha",
|
"captcha",
|
||||||
"chrono",
|
"chrono",
|
||||||
"elementtree",
|
"elementtree",
|
||||||
"itertools 0.12.0",
|
|
||||||
"lemmy_api_common",
|
"lemmy_api_common",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"lemmy_db_views",
|
"lemmy_db_views",
|
||||||
|
|
|
@ -33,7 +33,6 @@ anyhow = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
itertools = { workspace = true }
|
|
||||||
wav = "1.0.0"
|
wav = "1.0.0"
|
||||||
sitemap-rs = "0.2.0"
|
sitemap-rs = "0.2.0"
|
||||||
totp-rs = { version = "5.5.1", features = ["gen_secret", "otpauth"] }
|
totp-rs = { version = "5.5.1", features = ["gen_secret", "otpauth"] }
|
||||||
|
|
|
@ -3,19 +3,26 @@ use actix_web::{http::header::Header, HttpRequest};
|
||||||
use actix_web_httpauth::headers::authorization::{Authorization, Bearer};
|
use actix_web_httpauth::headers::authorization::{Authorization, Bearer};
|
||||||
use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine};
|
use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine};
|
||||||
use captcha::Captcha;
|
use captcha::Captcha;
|
||||||
use itertools::Itertools;
|
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
community::BanFromCommunity,
|
community::BanFromCommunity,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{check_user_valid, local_site_to_slur_regex, AUTH_COOKIE_NAME},
|
utils::{check_expire_time, check_user_valid, local_site_to_slur_regex, AUTH_COOKIE_NAME},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{
|
use lemmy_db_schema::{
|
||||||
comment::Comment,
|
source::{
|
||||||
local_site::LocalSite,
|
community::{
|
||||||
person::Person,
|
CommunityFollower,
|
||||||
post::Post,
|
CommunityFollowerForm,
|
||||||
|
CommunityPersonBan,
|
||||||
|
CommunityPersonBanForm,
|
||||||
|
},
|
||||||
|
local_site::LocalSite,
|
||||||
|
moderator::{ModBanFromCommunity, ModBanFromCommunityForm},
|
||||||
|
person::Person,
|
||||||
|
},
|
||||||
|
traits::{Bannable, Crud, Followable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -150,35 +157,77 @@ pub(crate) fn build_totp_2fa(
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Since removals and bans are only federated for local users,
|
/// Site bans are only federated for local users.
|
||||||
/// you also need to send bans for their content to local communities.
|
/// This is a problem, because site-banning non-local users will still leave content
|
||||||
|
/// they've posted to our local communities, on other servers.
|
||||||
|
///
|
||||||
|
/// So when doing a site ban for a non-local user, you need to federate/send a
|
||||||
|
/// community ban for every local community they've participated in.
|
||||||
/// See https://github.com/LemmyNet/lemmy/issues/4118
|
/// See https://github.com/LemmyNet/lemmy/issues/4118
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub(crate) async fn send_bans_and_removals_to_local_communities(
|
pub(crate) async fn ban_nonlocal_user_from_local_communities(
|
||||||
local_user_view: &LocalUserView,
|
local_user_view: &LocalUserView,
|
||||||
target: &Person,
|
target: &Person,
|
||||||
|
ban: bool,
|
||||||
reason: &Option<String>,
|
reason: &Option<String>,
|
||||||
remove_data: &Option<bool>,
|
remove_data: &Option<bool>,
|
||||||
|
expires: &Option<i64>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let posts_community_ids =
|
let ids = Person::list_local_community_ids(&mut context.pool(), target.id).await?;
|
||||||
Post::list_creators_local_community_ids(&mut context.pool(), target.id).await?;
|
|
||||||
let comments_community_ids =
|
|
||||||
Comment::list_creators_local_community_ids(&mut context.pool(), target.id).await?;
|
|
||||||
|
|
||||||
let ids = [posts_community_ids, comments_community_ids]
|
|
||||||
.concat()
|
|
||||||
.into_iter()
|
|
||||||
.unique();
|
|
||||||
|
|
||||||
for community_id in ids {
|
for community_id in ids {
|
||||||
|
let expires_dt = check_expire_time(*expires)?;
|
||||||
|
|
||||||
|
// Ban / unban them from our local communities
|
||||||
|
let community_user_ban_form = CommunityPersonBanForm {
|
||||||
|
community_id,
|
||||||
|
person_id: target.id,
|
||||||
|
expires: Some(expires_dt),
|
||||||
|
};
|
||||||
|
|
||||||
|
if ban {
|
||||||
|
CommunityPersonBan::ban(&mut context.pool(), &community_user_ban_form)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
// Also unsubscribe them from the community, if they are subscribed
|
||||||
|
let community_follower_form = CommunityFollowerForm {
|
||||||
|
community_id,
|
||||||
|
person_id: target.id,
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
} else {
|
||||||
|
CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mod tables
|
||||||
|
let form = ModBanFromCommunityForm {
|
||||||
|
mod_person_id: local_user_view.person.id,
|
||||||
|
other_person_id: target.id,
|
||||||
|
community_id,
|
||||||
|
reason: reason.clone(),
|
||||||
|
banned: Some(ban),
|
||||||
|
expires: expires_dt,
|
||||||
|
};
|
||||||
|
|
||||||
|
ModBanFromCommunity::create(&mut context.pool(), &form).await?;
|
||||||
|
|
||||||
|
// Federate the ban from community
|
||||||
let ban_from_community = BanFromCommunity {
|
let ban_from_community = BanFromCommunity {
|
||||||
community_id,
|
community_id,
|
||||||
person_id: target.id,
|
person_id: target.id,
|
||||||
ban: true,
|
ban,
|
||||||
remove_data: *remove_data,
|
|
||||||
reason: reason.clone(),
|
reason: reason.clone(),
|
||||||
expires: None,
|
remove_data: *remove_data,
|
||||||
|
expires: *expires,
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::send_bans_and_removals_to_local_communities;
|
use crate::ban_nonlocal_user_from_local_communities;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
|
@ -72,14 +72,18 @@ pub async fn ban_from_site(
|
||||||
|
|
||||||
let person_view = PersonView::read(&mut context.pool(), person.id).await?;
|
let person_view = PersonView::read(&mut context.pool(), person.id).await?;
|
||||||
|
|
||||||
send_bans_and_removals_to_local_communities(
|
if !person.local {
|
||||||
&local_user_view,
|
ban_nonlocal_user_from_local_communities(
|
||||||
&person,
|
&local_user_view,
|
||||||
&data.reason,
|
&person,
|
||||||
&data.remove_data,
|
data.ban,
|
||||||
&context,
|
&data.reason,
|
||||||
)
|
&data.remove_data,
|
||||||
.await?;
|
&data.expires,
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::BanFromSite {
|
SendActivityData::BanFromSite {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{CommentId, CommunityId, DbUrl, PersonId},
|
newtypes::{CommentId, DbUrl, PersonId},
|
||||||
schema::{comment, community, post},
|
schema::comment,
|
||||||
source::comment::{
|
source::comment::{
|
||||||
Comment,
|
Comment,
|
||||||
CommentInsertForm,
|
CommentInsertForm,
|
||||||
|
@ -17,7 +17,6 @@ use diesel::{
|
||||||
dsl::{insert_into, sql_query},
|
dsl::{insert_into, sql_query},
|
||||||
result::Error,
|
result::Error,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
JoinOnDsl,
|
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
@ -56,23 +55,6 @@ impl Comment {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lists local community ids for all comments for a given creator.
|
|
||||||
pub async fn list_creators_local_community_ids(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
for_creator_id: PersonId,
|
|
||||||
) -> Result<Vec<CommunityId>, Error> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
comment::table
|
|
||||||
.inner_join(post::table)
|
|
||||||
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
|
||||||
.filter(community::local.eq(true))
|
|
||||||
.filter(comment::creator_id.eq(for_creator_id))
|
|
||||||
.select(community::id)
|
|
||||||
.distinct()
|
|
||||||
.load::<CommunityId>(conn)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
comment_form: &CommentInsertForm,
|
comment_form: &CommentInsertForm,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
|
newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
|
||||||
schema::{instance, local_user, person, person_follower},
|
schema::{comment, community, instance, local_user, person, person_follower, post},
|
||||||
source::person::{
|
source::person::{
|
||||||
Person,
|
Person,
|
||||||
PersonFollower,
|
PersonFollower,
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
traits::{ApubActor, Crud, Followable},
|
traits::{ApubActor, Crud, Followable},
|
||||||
utils::{functions::lower, get_conn, naive_now, DbPool},
|
utils::{functions::lower, get_conn, naive_now, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, JoinOnDsl, QueryDsl};
|
use diesel::{dsl::insert_into, result::Error, CombineDsl, ExpressionMethods, JoinOnDsl, QueryDsl};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -84,6 +84,29 @@ impl Person {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists local community ids for all posts and comments for a given creator.
|
||||||
|
pub async fn list_local_community_ids(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_creator_id: PersonId,
|
||||||
|
) -> Result<Vec<CommunityId>, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
comment::table
|
||||||
|
.inner_join(post::table)
|
||||||
|
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||||
|
.filter(community::local.eq(true))
|
||||||
|
.filter(comment::creator_id.eq(for_creator_id))
|
||||||
|
.select(community::id)
|
||||||
|
.union(
|
||||||
|
post::table
|
||||||
|
.inner_join(community::table)
|
||||||
|
.filter(community::local.eq(true))
|
||||||
|
.filter(post::creator_id.eq(for_creator_id))
|
||||||
|
.select(community::id),
|
||||||
|
)
|
||||||
|
.load::<CommunityId>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PersonInsertForm {
|
impl PersonInsertForm {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{CommunityId, DbUrl, PersonId, PostId},
|
newtypes::{CommunityId, DbUrl, PersonId, PostId},
|
||||||
schema::{community, post},
|
schema::post,
|
||||||
source::post::{
|
source::post::{
|
||||||
Post,
|
Post,
|
||||||
PostInsertForm,
|
PostInsertForm,
|
||||||
|
@ -236,22 +236,6 @@ impl Post {
|
||||||
.get_results::<Self>(conn)
|
.get_results::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lists local community ids for all posts for a given creator.
|
|
||||||
pub async fn list_creators_local_community_ids(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
for_creator_id: PersonId,
|
|
||||||
) -> Result<Vec<CommunityId>, Error> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
post::table
|
|
||||||
.inner_join(community::table)
|
|
||||||
.filter(community::local.eq(true))
|
|
||||||
.filter(post::creator_id.eq(for_creator_id))
|
|
||||||
.select(community::id)
|
|
||||||
.distinct()
|
|
||||||
.load::<CommunityId>(conn)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
Loading…
Reference in New Issue