mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-05 20:15:01 +00:00
convert community receivers
This commit is contained in:
parent
fb0932e0e6
commit
27c12ce411
13 changed files with 483 additions and 548 deletions
|
@ -1,232 +0,0 @@
|
|||
use crate::{
|
||||
activities::receive::get_actor_as_person,
|
||||
inbox::receive_for_community::verify_actor_is_community_mod,
|
||||
};
|
||||
use activitystreams::{
|
||||
activity::{ActorAndObjectRefExt, Delete, Undo, Update},
|
||||
base::ExtendsExt,
|
||||
};
|
||||
use anyhow::{anyhow, Context};
|
||||
use lemmy_api_common::{blocking, community::CommunityResponse};
|
||||
use lemmy_apub::{
|
||||
get_community_from_to_or_cc,
|
||||
objects::FromApubToForm,
|
||||
ActorType,
|
||||
CommunityType,
|
||||
GroupExt,
|
||||
};
|
||||
use lemmy_db_queries::{source::community::Community_, Crud};
|
||||
use lemmy_db_schema::source::{
|
||||
community::{Community, CommunityForm},
|
||||
person::Person,
|
||||
};
|
||||
use lemmy_db_views_actor::{
|
||||
community_moderator_view::CommunityModeratorView,
|
||||
community_view::CommunityView,
|
||||
};
|
||||
use lemmy_utils::{location_info, LemmyError};
|
||||
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperationCrud};
|
||||
|
||||
/// This activity is received from a remote community mod, and updates the description or other
|
||||
/// fields of a local community.
|
||||
pub(crate) async fn receive_remote_mod_update_community(
|
||||
update: Update,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = get_community_from_to_or_cc(&update, context, request_counter).await?;
|
||||
verify_actor_is_community_mod(&update, &community, context).await?;
|
||||
let group = GroupExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
||||
.context(location_info!())?;
|
||||
let updated_community = CommunityForm::from_apub(
|
||||
&group,
|
||||
context,
|
||||
community.actor_id(),
|
||||
request_counter,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let cf = CommunityForm {
|
||||
name: updated_community.name,
|
||||
title: updated_community.title,
|
||||
description: updated_community.description,
|
||||
nsfw: updated_community.nsfw,
|
||||
// TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
|
||||
icon: updated_community.icon,
|
||||
banner: updated_community.banner,
|
||||
..CommunityForm::default()
|
||||
};
|
||||
blocking(context.pool(), move |conn| {
|
||||
Community::update(conn, community.id, &cf)
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_remote_mod_delete_community(
|
||||
delete: Delete,
|
||||
community: Community,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_actor_is_community_mod(&delete, &community, context).await?;
|
||||
let actor = get_actor_as_person(&delete, context, request_counter).await?;
|
||||
verify_is_remote_community_creator(&actor, &community, context).await?;
|
||||
let community_id = community.id;
|
||||
blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community_id, true)
|
||||
})
|
||||
.await??;
|
||||
community.send_delete(actor, context).await
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_delete_community(
|
||||
context: &LemmyContext,
|
||||
community: Community,
|
||||
) -> Result<(), LemmyError> {
|
||||
let deleted_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community.id, true)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let community_id = deleted_community.id;
|
||||
let res = CommunityResponse {
|
||||
community_view: blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, None)
|
||||
})
|
||||
.await??,
|
||||
};
|
||||
|
||||
let community_id = res.community_view.community.id;
|
||||
context.chat_server().do_send(SendCommunityRoomMessage {
|
||||
op: UserOperationCrud::EditCommunity,
|
||||
response: res,
|
||||
community_id,
|
||||
websocket_id: None,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_remove_community(
|
||||
context: &LemmyContext,
|
||||
community: Community,
|
||||
) -> Result<(), LemmyError> {
|
||||
let removed_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_removed(conn, community.id, true)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let community_id = removed_community.id;
|
||||
let res = CommunityResponse {
|
||||
community_view: blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, None)
|
||||
})
|
||||
.await??,
|
||||
};
|
||||
|
||||
let community_id = res.community_view.community.id;
|
||||
context.chat_server().do_send(SendCommunityRoomMessage {
|
||||
op: UserOperationCrud::EditCommunity,
|
||||
response: res,
|
||||
community_id,
|
||||
websocket_id: None,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_remote_mod_undo_delete_community(
|
||||
undo: Undo,
|
||||
community: Community,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_actor_is_community_mod(&undo, &community, context).await?;
|
||||
let actor = get_actor_as_person(&undo, context, request_counter).await?;
|
||||
verify_is_remote_community_creator(&actor, &community, context).await?;
|
||||
let community_id = community.id;
|
||||
blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community_id, false)
|
||||
})
|
||||
.await??;
|
||||
community.send_undo_delete(actor, context).await
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_undo_delete_community(
|
||||
context: &LemmyContext,
|
||||
community: Community,
|
||||
) -> Result<(), LemmyError> {
|
||||
let deleted_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community.id, false)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let community_id = deleted_community.id;
|
||||
let res = CommunityResponse {
|
||||
community_view: blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, None)
|
||||
})
|
||||
.await??,
|
||||
};
|
||||
|
||||
let community_id = res.community_view.community.id;
|
||||
context.chat_server().do_send(SendCommunityRoomMessage {
|
||||
op: UserOperationCrud::EditCommunity,
|
||||
response: res,
|
||||
community_id,
|
||||
websocket_id: None,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_undo_remove_community(
|
||||
context: &LemmyContext,
|
||||
community: Community,
|
||||
) -> Result<(), LemmyError> {
|
||||
let removed_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_removed(conn, community.id, false)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let community_id = removed_community.id;
|
||||
let res = CommunityResponse {
|
||||
community_view: blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, None)
|
||||
})
|
||||
.await??,
|
||||
};
|
||||
|
||||
let community_id = res.community_view.community.id;
|
||||
|
||||
context.chat_server().do_send(SendCommunityRoomMessage {
|
||||
op: UserOperationCrud::EditCommunity,
|
||||
response: res,
|
||||
community_id,
|
||||
websocket_id: None,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the remote user is creator of the local community. This can only happen if a community
|
||||
/// is created by a local user, and then transferred to a remote user.
|
||||
async fn verify_is_remote_community_creator(
|
||||
user: &Person,
|
||||
community: &Community,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community_id = community.id;
|
||||
let community_mods = blocking(context.pool(), move |conn| {
|
||||
CommunityModeratorView::for_community(conn, community_id)
|
||||
})
|
||||
.await??;
|
||||
|
||||
if user.id != community_mods[0].moderator.id {
|
||||
Err(anyhow!("Actor is not community creator").into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ use std::fmt::Debug;
|
|||
use url::Url;
|
||||
|
||||
pub(crate) mod comment_undo;
|
||||
pub(crate) mod community;
|
||||
pub(crate) mod post_undo;
|
||||
|
||||
/// Return HTTP 501 for unsupported activities in inbox.
|
||||
|
|
95
crates/apub_receive/src/activities_new/community/delete.rs
Normal file
95
crates/apub_receive/src/activities_new/community/delete.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use crate::{
|
||||
activities_new::community::{send_websocket_message, verify_is_community_mod},
|
||||
inbox::new_inbox_routing::Activity,
|
||||
};
|
||||
use activitystreams::activity::kind::DeleteType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::{
|
||||
check_is_apub_id_valid,
|
||||
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
|
||||
ActorType,
|
||||
CommunityType,
|
||||
};
|
||||
use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::{source::community::Community_, ApubObject};
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||
use url::Url;
|
||||
|
||||
// We have two possibilities which need to be handled:
|
||||
// 1. actor is remote mod, community id in object
|
||||
// 2. actor is community, cc is followers collection
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteCommunity {
|
||||
actor: Url,
|
||||
to: PublicUrl,
|
||||
pub(in crate::activities_new::community) object: Url,
|
||||
cc: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: DeleteType,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl VerifyActivity for Activity<DeleteCommunity> {
|
||||
async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
let object = self.inner.object.clone();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object.into())
|
||||
})
|
||||
.await?;
|
||||
// remote mod action on local community
|
||||
if let Ok(c) = community {
|
||||
verify_domains_match(&self.inner.object, &self.inner.cc)?;
|
||||
check_is_apub_id_valid(&self.inner.actor, false)?;
|
||||
verify_is_community_mod(self.inner.actor.clone(), c.actor_id(), context).await
|
||||
}
|
||||
// community action sent to followers
|
||||
else {
|
||||
verify_domains_match(&self.inner.actor, &self.inner.object)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ReceiveActivity for Activity<DeleteCommunity> {
|
||||
async fn receive(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = self.inner.object.clone();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &actor.into())
|
||||
})
|
||||
.await?;
|
||||
let community_id = match community {
|
||||
Ok(c) => {
|
||||
// remote mod sent delete to local community, forward it to followers
|
||||
let actor =
|
||||
get_or_fetch_and_upsert_person(&self.inner.actor, context, request_counter).await?;
|
||||
c.send_delete(actor, context).await?;
|
||||
c.id
|
||||
}
|
||||
Err(_) => {
|
||||
// refetch the remote community
|
||||
let community =
|
||||
get_or_fetch_and_upsert_community(&self.inner.object, context, request_counter).await?;
|
||||
community.id
|
||||
}
|
||||
};
|
||||
let deleted_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community_id, true)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_websocket_message(
|
||||
deleted_community.id,
|
||||
UserOperationCrud::DeleteCommunity,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
62
crates/apub_receive/src/activities_new/community/mod.rs
Normal file
62
crates/apub_receive/src/activities_new/community/mod.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use anyhow::anyhow;
|
||||
use lemmy_api_common::{blocking, community::CommunityResponse};
|
||||
use lemmy_db_queries::ApubObject;
|
||||
use lemmy_db_schema::{
|
||||
source::{community::Community, person::Person},
|
||||
CommunityId,
|
||||
};
|
||||
use lemmy_db_views_actor::community_view::CommunityView;
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext};
|
||||
use url::Url;
|
||||
|
||||
pub mod delete;
|
||||
pub mod remove;
|
||||
pub mod undo_delete;
|
||||
pub mod undo_remove;
|
||||
pub mod update;
|
||||
|
||||
async fn send_websocket_message<OP: ToString + Send + lemmy_websocket::OperationType + 'static>(
|
||||
community_id: CommunityId,
|
||||
op: OP,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community_view = blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, None)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let res = CommunityResponse { community_view };
|
||||
|
||||
context.chat_server().do_send(SendCommunityRoomMessage {
|
||||
op,
|
||||
response: res,
|
||||
community_id,
|
||||
websocket_id: None,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn verify_is_community_mod(
|
||||
actor: Url,
|
||||
community: Url,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = blocking(context.pool(), move |conn| {
|
||||
Person::read_from_apub_id(conn, &actor.into())
|
||||
})
|
||||
.await??;
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &community.into())
|
||||
})
|
||||
.await??;
|
||||
let is_mod_or_admin = blocking(context.pool(), move |conn| {
|
||||
CommunityView::is_mod_or_admin(conn, actor.id, community.id)
|
||||
})
|
||||
.await?;
|
||||
if !is_mod_or_admin {
|
||||
return Err(anyhow!("Not a mod").into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
60
crates/apub_receive/src/activities_new/community/remove.rs
Normal file
60
crates/apub_receive/src/activities_new/community/remove.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use crate::{
|
||||
activities_new::community::send_websocket_message,
|
||||
inbox::new_inbox_routing::Activity,
|
||||
};
|
||||
use activitystreams::activity::kind::RemoveType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::check_is_apub_id_valid;
|
||||
use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::{source::community::Community_, ApubObject};
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RemoveCommunity {
|
||||
actor: Url,
|
||||
to: PublicUrl,
|
||||
pub(in crate::activities_new::community) object: Url,
|
||||
cc: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: RemoveType,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl VerifyActivity for Activity<RemoveCommunity> {
|
||||
async fn verify(&self, _context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
check_is_apub_id_valid(&self.inner.actor, false)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.object)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.cc)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ReceiveActivity for Activity<RemoveCommunity> {
|
||||
async fn receive(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let object = self.inner.object.clone();
|
||||
// only search in local database, there is no reason to fetch something thats deleted
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object.into())
|
||||
})
|
||||
.await??;
|
||||
let removed_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_removed(conn, community.id, true)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_websocket_message(
|
||||
removed_community.id,
|
||||
UserOperationCrud::RemoveCommunity,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
104
crates/apub_receive/src/activities_new/community/undo_delete.rs
Normal file
104
crates/apub_receive/src/activities_new/community/undo_delete.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use crate::{
|
||||
activities_new::community::{
|
||||
delete::DeleteCommunity,
|
||||
send_websocket_message,
|
||||
verify_is_community_mod,
|
||||
},
|
||||
inbox::new_inbox_routing::Activity,
|
||||
};
|
||||
use activitystreams::activity::kind::DeleteType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::{
|
||||
check_is_apub_id_valid,
|
||||
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
|
||||
ActorType,
|
||||
CommunityType,
|
||||
};
|
||||
use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::{source::community::Community_, ApubObject};
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||
use url::Url;
|
||||
|
||||
// We have two possibilities which need to be handled:
|
||||
// 1. actor is remote mod, community id in object
|
||||
// 2. actor is community, cc is followers collection
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoDeleteCommunity {
|
||||
actor: Url,
|
||||
to: PublicUrl,
|
||||
object: Activity<DeleteCommunity>,
|
||||
cc: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: DeleteType,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl VerifyActivity for Activity<UndoDeleteCommunity> {
|
||||
async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
let object = self.inner.object.inner.object.clone();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object.into())
|
||||
})
|
||||
.await?;
|
||||
// remote mod action on local community
|
||||
if let Ok(c) = community {
|
||||
verify_domains_match(&self.inner.object.inner.object, &self.inner.cc)?;
|
||||
check_is_apub_id_valid(&self.inner.actor, false)?;
|
||||
verify_is_community_mod(self.inner.actor.clone(), c.actor_id(), context).await?;
|
||||
}
|
||||
// community action sent to followers
|
||||
else {
|
||||
verify_domains_match(&self.inner.actor, &self.inner.object.inner.object)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.cc)?;
|
||||
}
|
||||
self.inner.object.verify(context).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ReceiveActivity for Activity<UndoDeleteCommunity> {
|
||||
async fn receive(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = self.inner.object.inner.object.clone();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &actor.into())
|
||||
})
|
||||
.await?;
|
||||
let community_id = match community {
|
||||
Ok(c) => {
|
||||
// remote mod sent undo to local community, forward it to followers
|
||||
let actor =
|
||||
get_or_fetch_and_upsert_person(&self.inner.actor, context, request_counter).await?;
|
||||
c.send_delete(actor, context).await?;
|
||||
c.id
|
||||
}
|
||||
Err(_) => {
|
||||
// refetch the remote community
|
||||
let community = get_or_fetch_and_upsert_community(
|
||||
&self.inner.object.inner.object,
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await?;
|
||||
community.id
|
||||
}
|
||||
};
|
||||
let restored_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_deleted(conn, community_id, false)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_websocket_message(
|
||||
restored_community.id,
|
||||
UserOperationCrud::EditCommunity,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
use crate::{
|
||||
activities_new::community::{remove::RemoveCommunity, send_websocket_message},
|
||||
inbox::new_inbox_routing::Activity,
|
||||
};
|
||||
use activitystreams::activity::kind::RemoveType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::{check_is_apub_id_valid, fetcher::community::get_or_fetch_and_upsert_community};
|
||||
use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::source::community::Community_;
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoRemoveCommunity {
|
||||
actor: Url,
|
||||
to: PublicUrl,
|
||||
object: Activity<RemoveCommunity>,
|
||||
cc: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: RemoveType,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl VerifyActivity for Activity<UndoRemoveCommunity> {
|
||||
async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
check_is_apub_id_valid(&self.inner.actor, false)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.object.inner.object)?;
|
||||
verify_domains_match(&self.inner.actor, &self.inner.cc)?;
|
||||
self.inner.object.verify(context).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ReceiveActivity for Activity<UndoRemoveCommunity> {
|
||||
async fn receive(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community_id = self.inner.object.inner.object.clone();
|
||||
let community =
|
||||
get_or_fetch_and_upsert_community(&community_id, context, request_counter).await?;
|
||||
|
||||
let restored_community = blocking(context.pool(), move |conn| {
|
||||
Community::update_removed(conn, community.id, false)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_websocket_message(
|
||||
restored_community.id,
|
||||
UserOperationCrud::EditCommunity,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
80
crates/apub_receive/src/activities_new/community/update.rs
Normal file
80
crates/apub_receive/src/activities_new/community/update.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use crate::{
|
||||
activities_new::community::{send_websocket_message, verify_is_community_mod},
|
||||
inbox::new_inbox_routing::Activity,
|
||||
};
|
||||
use activitystreams::{activity::kind::UpdateType, base::BaseExt};
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::{check_is_apub_id_valid, objects::FromApubToForm, GroupExt};
|
||||
use lemmy_apub_lib::{PublicUrl, ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::{ApubObject, Crud};
|
||||
use lemmy_db_schema::source::community::{Community, CommunityForm};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||
use url::Url;
|
||||
|
||||
/// This activity is received from a remote community mod, and updates the description or other
|
||||
/// fields of a local community.
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpdateCommunity {
|
||||
actor: Url,
|
||||
to: PublicUrl,
|
||||
object: GroupExt,
|
||||
cc: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: UpdateType,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl VerifyActivity for Activity<UpdateCommunity> {
|
||||
async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
self.inner.object.id(self.inner.cc.as_str())?;
|
||||
check_is_apub_id_valid(&self.inner.actor, false)?;
|
||||
verify_is_community_mod(self.inner.actor.clone(), self.inner.cc.clone(), context).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ReceiveActivity for Activity<UpdateCommunity> {
|
||||
async fn receive(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let cc = self.inner.cc.clone().into();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &cc)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let updated_community = CommunityForm::from_apub(
|
||||
&self.inner.object,
|
||||
context,
|
||||
community.actor_id.clone().into(),
|
||||
request_counter,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let cf = CommunityForm {
|
||||
name: updated_community.name,
|
||||
title: updated_community.title,
|
||||
description: updated_community.description,
|
||||
nsfw: updated_community.nsfw,
|
||||
// TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
|
||||
icon: updated_community.icon,
|
||||
banner: updated_community.banner,
|
||||
..CommunityForm::default()
|
||||
};
|
||||
let updated_community = blocking(context.pool(), move |conn| {
|
||||
Community::update(conn, community.id, &cf)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_websocket_message(
|
||||
updated_community.id,
|
||||
UserOperationCrud::EditCommunity,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use lemmy_websocket::LemmyContext;
|
|||
use url::Url;
|
||||
|
||||
pub mod comment;
|
||||
pub mod community;
|
||||
pub mod follow;
|
||||
pub mod post;
|
||||
pub mod private_message;
|
||||
|
|
|
@ -8,10 +8,8 @@ use crate::{
|
|||
receive_for_community::{
|
||||
receive_add_for_community,
|
||||
receive_block_user_for_community,
|
||||
receive_delete_for_community,
|
||||
receive_remove_for_community,
|
||||
receive_undo_for_community,
|
||||
receive_update_for_community,
|
||||
},
|
||||
verify_is_addressed_to_public,
|
||||
},
|
||||
|
@ -155,30 +153,10 @@ pub(crate) async fn community_receive_message(
|
|||
.await?
|
||||
}
|
||||
CommunityValidTypes::Create => todo!(),
|
||||
CommunityValidTypes::Update => {
|
||||
Box::pin(receive_update_for_community(
|
||||
context,
|
||||
any_base.clone(),
|
||||
None,
|
||||
&actor_url,
|
||||
request_counter,
|
||||
))
|
||||
.await?;
|
||||
true
|
||||
}
|
||||
CommunityValidTypes::Update => todo!(),
|
||||
CommunityValidTypes::Like => todo!(),
|
||||
CommunityValidTypes::Dislike => todo!(),
|
||||
CommunityValidTypes::Delete => {
|
||||
Box::pin(receive_delete_for_community(
|
||||
context,
|
||||
any_base.clone(),
|
||||
None,
|
||||
&actor_url,
|
||||
request_counter,
|
||||
))
|
||||
.await?;
|
||||
true
|
||||
}
|
||||
CommunityValidTypes::Delete => todo!(),
|
||||
CommunityValidTypes::Add => {
|
||||
Box::pin(receive_add_for_community(
|
||||
context,
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::activities_new::{
|
|||
remove::RemoveComment,
|
||||
update::UpdateComment,
|
||||
},
|
||||
community::{delete::DeleteCommunity, update::UpdateCommunity},
|
||||
follow::AcceptFollowCommunity,
|
||||
post::{
|
||||
create::CreatePost,
|
||||
|
@ -28,9 +29,9 @@ use lemmy_apub_lib::{ReceiveActivity, VerifyActivity};
|
|||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use url::Url;
|
||||
|
||||
// TODO: add security checks for received activities back in
|
||||
// mainly check that domain of actor and id are identical (and object/object.id where applicable)
|
||||
use crate::activities_new::community::remove::RemoveCommunity;
|
||||
use crate::activities_new::community::undo_remove::UndoRemoveCommunity;
|
||||
use crate::activities_new::community::undo_delete::UndoDeleteCommunity;
|
||||
|
||||
// TODO: would be nice if we could move this to lemmy_apub_lib crate. doing that gives error:
|
||||
// "only traits defined in the current crate can be implemented for arbitrary types"
|
||||
|
@ -75,6 +76,11 @@ pub enum PersonAcceptedActivitiesNew {
|
|||
DislikePost(DislikePost),
|
||||
DeletePost(DeletePost),
|
||||
RemovePost(RemovePost),
|
||||
UpdateCommunity(UpdateCommunity),
|
||||
DeleteCommunity(DeleteCommunity),
|
||||
RemoveCommunity(RemoveCommunity),
|
||||
UndoDeleteCommunity(UndoDeleteCommunity),
|
||||
UndoRemoveCommunity(UndoRemoveCommunity),
|
||||
}
|
||||
|
||||
// todo: can probably get rid of these?
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
use crate::{
|
||||
activities::receive::{
|
||||
community::{
|
||||
receive_delete_community,
|
||||
receive_remove_community,
|
||||
receive_undo_delete_community,
|
||||
receive_undo_remove_community,
|
||||
},
|
||||
receive_unhandled_activity,
|
||||
verify_activity_domains_valid,
|
||||
},
|
||||
activities::receive::{receive_unhandled_activity, verify_activity_domains_valid},
|
||||
inbox::{
|
||||
is_activity_already_known,
|
||||
is_addressed_to_community_followers,
|
||||
|
@ -17,38 +8,30 @@ use crate::{
|
|||
receive_for_community::{
|
||||
receive_add_for_community,
|
||||
receive_block_user_for_community,
|
||||
receive_delete_for_community,
|
||||
receive_remove_for_community,
|
||||
receive_undo_for_community,
|
||||
receive_update_for_community,
|
||||
},
|
||||
verify_is_addressed_to_public,
|
||||
},
|
||||
};
|
||||
use activitystreams::{
|
||||
activity::{ActorAndObject, Announce, Delete, Remove, Undo},
|
||||
activity::{ActorAndObject, Announce},
|
||||
base::AnyBase,
|
||||
prelude::*,
|
||||
};
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use anyhow::{anyhow, Context};
|
||||
use diesel::NotFound;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub::{check_is_apub_id_valid, get_activity_to_and_cc, ActorType};
|
||||
use lemmy_apub_lib::{ReceiveActivity, VerifyActivity};
|
||||
use lemmy_db_queries::{ApubObject, Followable};
|
||||
use lemmy_db_schema::source::{
|
||||
community::{Community, CommunityFollower},
|
||||
person::Person,
|
||||
private_message::PrivateMessage,
|
||||
};
|
||||
use lemmy_db_queries::Followable;
|
||||
use lemmy_db_schema::source::{community::CommunityFollower, person::Person};
|
||||
use lemmy_utils::{location_info, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use strum_macros::EnumString;
|
||||
use url::Url;
|
||||
|
||||
/// Allowed activities for person inbox.
|
||||
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
|
||||
|
@ -135,7 +118,6 @@ pub(crate) async fn person_receive_message(
|
|||
|
||||
let any_base = activity.clone().into_any_base()?;
|
||||
let kind = activity.kind().context(location_info!())?;
|
||||
let actor_url = actor.actor_id();
|
||||
match kind {
|
||||
PersonValidTypes::Accept => {}
|
||||
PersonValidTypes::Announce => {
|
||||
|
@ -143,19 +125,9 @@ pub(crate) async fn person_receive_message(
|
|||
}
|
||||
PersonValidTypes::Create => {}
|
||||
PersonValidTypes::Update => {}
|
||||
PersonValidTypes::Delete => {
|
||||
Box::pin(receive_delete(
|
||||
context,
|
||||
any_base,
|
||||
&actor_url,
|
||||
request_counter,
|
||||
))
|
||||
.await?
|
||||
}
|
||||
PersonValidTypes::Undo => {
|
||||
Box::pin(receive_undo(context, any_base, &actor_url, request_counter)).await?
|
||||
}
|
||||
PersonValidTypes::Remove => Box::pin(receive_remove(context, any_base, &actor_url)).await?,
|
||||
PersonValidTypes::Delete => todo!(),
|
||||
PersonValidTypes::Undo => todo!(),
|
||||
PersonValidTypes::Remove => todo!(),
|
||||
};
|
||||
|
||||
// TODO: would be logical to move websocket notification code here
|
||||
|
@ -241,28 +213,10 @@ pub async fn receive_announce(
|
|||
use AnnouncableActivities::*;
|
||||
match kind {
|
||||
Some(Create) => todo!(),
|
||||
Some(Update) => {
|
||||
receive_update_for_community(
|
||||
context,
|
||||
inner_activity,
|
||||
Some(announce),
|
||||
&inner_id,
|
||||
request_counter,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Some(Update) => todo!(),
|
||||
Some(Like) => todo!(),
|
||||
Some(Dislike) => todo!(),
|
||||
Some(Delete) => {
|
||||
receive_delete_for_community(
|
||||
context,
|
||||
inner_activity,
|
||||
Some(announce),
|
||||
&inner_id,
|
||||
request_counter,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Some(Delete) => todo!(),
|
||||
Some(Remove) => {
|
||||
receive_remove_for_community(context, inner_activity, Some(announce), request_counter).await
|
||||
}
|
||||
|
@ -286,118 +240,3 @@ pub async fn receive_announce(
|
|||
_ => receive_unhandled_activity(inner_activity),
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive_delete(
|
||||
context: &LemmyContext,
|
||||
any_base: AnyBase,
|
||||
expected_domain: &Url,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
use CommunityOrPrivateMessage::*;
|
||||
|
||||
let delete = Delete::from_any_base(any_base.clone())?.context(location_info!())?;
|
||||
verify_activity_domains_valid(&delete, expected_domain, true)?;
|
||||
let object_uri = delete
|
||||
.object()
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
|
||||
match find_community_or_private_message_by_id(context, object_uri).await? {
|
||||
Community(c) => receive_delete_community(context, c).await,
|
||||
PrivateMessage(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive_remove(
|
||||
context: &LemmyContext,
|
||||
any_base: AnyBase,
|
||||
expected_domain: &Url,
|
||||
) -> Result<(), LemmyError> {
|
||||
let remove = Remove::from_any_base(any_base.clone())?.context(location_info!())?;
|
||||
verify_activity_domains_valid(&remove, expected_domain, true)?;
|
||||
let object_uri = remove
|
||||
.object()
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object_uri.into())
|
||||
})
|
||||
.await??;
|
||||
receive_remove_community(&context, community).await
|
||||
}
|
||||
|
||||
async fn receive_undo(
|
||||
context: &LemmyContext,
|
||||
any_base: AnyBase,
|
||||
expected_domain: &Url,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let undo = Undo::from_any_base(any_base)?.context(location_info!())?;
|
||||
verify_activity_domains_valid(&undo, expected_domain, true)?;
|
||||
|
||||
let inner_activity = undo.object().to_owned().one().context(location_info!())?;
|
||||
let kind = inner_activity.kind_str();
|
||||
match kind {
|
||||
Some("Delete") => {
|
||||
let delete = Delete::from_any_base(inner_activity)?.context(location_info!())?;
|
||||
verify_activity_domains_valid(&delete, expected_domain, true)?;
|
||||
let object_uri = delete
|
||||
.object()
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
use CommunityOrPrivateMessage::*;
|
||||
match find_community_or_private_message_by_id(context, object_uri).await? {
|
||||
Community(c) => receive_undo_delete_community(context, c).await,
|
||||
PrivateMessage(_) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Some("Remove") => {
|
||||
let remove = Remove::from_any_base(inner_activity)?.context(location_info!())?;
|
||||
let object_uri = remove
|
||||
.object()
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object_uri.into())
|
||||
})
|
||||
.await??;
|
||||
receive_undo_remove_community(context, community).await
|
||||
}
|
||||
_ => receive_unhandled_activity(undo),
|
||||
}
|
||||
}
|
||||
enum CommunityOrPrivateMessage {
|
||||
Community(Community),
|
||||
PrivateMessage(PrivateMessage),
|
||||
}
|
||||
|
||||
async fn find_community_or_private_message_by_id(
|
||||
context: &LemmyContext,
|
||||
apub_id: Url,
|
||||
) -> Result<CommunityOrPrivateMessage, LemmyError> {
|
||||
let ap_id = apub_id.to_owned();
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &ap_id.into())
|
||||
})
|
||||
.await?;
|
||||
if let Ok(c) = community {
|
||||
return Ok(CommunityOrPrivateMessage::Community(c));
|
||||
}
|
||||
|
||||
let ap_id = apub_id.to_owned();
|
||||
let private_message = blocking(context.pool(), move |conn| {
|
||||
PrivateMessage::read_from_apub_id(conn, &ap_id.into())
|
||||
})
|
||||
.await?;
|
||||
if let Ok(p) = private_message {
|
||||
return Ok(CommunityOrPrivateMessage::PrivateMessage(p));
|
||||
}
|
||||
|
||||
Err(NotFound.into())
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@ use crate::{
|
|||
receive_undo_like_comment,
|
||||
receive_undo_remove_comment,
|
||||
},
|
||||
community::{
|
||||
receive_remote_mod_delete_community,
|
||||
receive_remote_mod_undo_delete_community,
|
||||
receive_remote_mod_update_community,
|
||||
},
|
||||
post_undo::{
|
||||
receive_undo_delete_post,
|
||||
receive_undo_dislike_post,
|
||||
|
@ -34,7 +29,6 @@ use activitystreams::{
|
|||
OptTargetRef,
|
||||
Remove,
|
||||
Undo,
|
||||
Update,
|
||||
},
|
||||
base::AnyBase,
|
||||
object::AsObject,
|
||||
|
@ -51,7 +45,6 @@ use lemmy_apub::{
|
|||
find_object_by_id,
|
||||
find_post_or_comment_by_id,
|
||||
generate_moderators_url,
|
||||
ActorType,
|
||||
CommunityType,
|
||||
Object,
|
||||
PostOrComment,
|
||||
|
@ -101,66 +94,6 @@ enum ObjectTypes {
|
|||
/// This file is for post/comment activities received by the community, and for post/comment
|
||||
/// activities announced by the community and received by the person.
|
||||
|
||||
/// A post or comment being edited
|
||||
pub(in crate::inbox) async fn receive_update_for_community(
|
||||
context: &LemmyContext,
|
||||
activity: AnyBase,
|
||||
announce: Option<Announce>,
|
||||
expected_domain: &Url,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let update = Update::from_any_base(activity.to_owned())?.context(location_info!())?;
|
||||
verify_activity_domains_valid(&update, &expected_domain, false)?;
|
||||
verify_is_addressed_to_public(&update)?;
|
||||
verify_modification_actor_instance(&update, &announce, context, request_counter).await?;
|
||||
|
||||
let kind = update
|
||||
.object()
|
||||
.as_single_kind_str()
|
||||
.and_then(|s| s.parse().ok());
|
||||
match kind {
|
||||
Some(ObjectTypes::Page) => todo!(),
|
||||
Some(ObjectTypes::Note) => todo!(),
|
||||
Some(ObjectTypes::Group) => {
|
||||
receive_remote_mod_update_community(update, context, request_counter).await
|
||||
}
|
||||
_ => receive_unhandled_activity(update),
|
||||
}
|
||||
}
|
||||
|
||||
/// A post or comment being deleted by its creator
|
||||
pub(in crate::inbox) async fn receive_delete_for_community(
|
||||
context: &LemmyContext,
|
||||
activity: AnyBase,
|
||||
announce: Option<Announce>,
|
||||
expected_domain: &Url,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let delete = Delete::from_any_base(activity)?.context(location_info!())?;
|
||||
// TODO: skip this check if action is done by remote mod
|
||||
verify_is_addressed_to_public(&delete)?;
|
||||
verify_modification_actor_instance(&delete, &announce, context, request_counter).await?;
|
||||
|
||||
let object = delete
|
||||
.object()
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
|
||||
match find_object_by_id(context, object).await {
|
||||
Ok(Object::Post(_)) => todo!(),
|
||||
Ok(Object::Comment(_)) => {
|
||||
verify_activity_domains_valid(&delete, &expected_domain, true)?;
|
||||
todo!()
|
||||
}
|
||||
Ok(Object::Community(c)) => {
|
||||
receive_remote_mod_delete_community(delete, *c, context, request_counter).await
|
||||
}
|
||||
// if we dont have the object or dont support its deletion, no need to do anything
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// A post or comment being removed by a mod/admin
|
||||
pub(in crate::inbox) async fn receive_remove_for_community(
|
||||
context: &LemmyContext,
|
||||
|
@ -258,7 +191,7 @@ pub(in crate::inbox) async fn receive_undo_delete_for_community(
|
|||
context: &LemmyContext,
|
||||
undo: Undo,
|
||||
expected_domain: &Url,
|
||||
request_counter: &mut i32,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let delete = Delete::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
|
||||
.context(location_info!())?;
|
||||
|
@ -278,10 +211,7 @@ pub(in crate::inbox) async fn receive_undo_delete_for_community(
|
|||
verify_activity_domains_valid(&delete, &expected_domain, true)?;
|
||||
receive_undo_delete_comment(context, *c).await
|
||||
}
|
||||
Ok(Object::Community(c)) => {
|
||||
verify_actor_is_community_mod(&undo, &c, context).await?;
|
||||
receive_remote_mod_undo_delete_community(undo, *c, context, request_counter).await
|
||||
}
|
||||
Ok(Object::Community(_)) => todo!(),
|
||||
// if we dont have the object or dont support its deletion, no need to do anything
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -622,52 +552,6 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// For activities like Update, Delete or Remove, check that the actor is from the same instance
|
||||
/// as the original object itself (or is a remote mod).
|
||||
///
|
||||
/// Note: This is only needed for mod actions. Normal user actions (edit post, undo vote etc) are
|
||||
/// already verified with `expected_domain`, so this serves as an additional check.
|
||||
async fn verify_modification_actor_instance<T, Kind>(
|
||||
activity: &T,
|
||||
announce: &Option<Announce>,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError>
|
||||
where
|
||||
T: ActorAndObjectRef + BaseExt<Kind> + AsObject<Kind>,
|
||||
{
|
||||
let actor_id = activity
|
||||
.actor()?
|
||||
.to_owned()
|
||||
.single_xsd_any_uri()
|
||||
.context(location_info!())?;
|
||||
let object_id = activity
|
||||
.object()
|
||||
.as_one()
|
||||
.map(|o| o.id())
|
||||
.flatten()
|
||||
.context(location_info!())?;
|
||||
let original_id = match fetch_post_or_comment_by_id(object_id, context, request_counter).await {
|
||||
Ok(PostOrComment::Post(p)) => p.ap_id.into_inner(),
|
||||
Ok(PostOrComment::Comment(c)) => c.ap_id.into_inner(),
|
||||
Err(_) => {
|
||||
// We can also receive Update activity from remote mod for local activity
|
||||
let object_id = object_id.to_owned().into();
|
||||
blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &object_id)
|
||||
})
|
||||
.await??
|
||||
.actor_id()
|
||||
}
|
||||
};
|
||||
if actor_id.domain() != original_id.domain() {
|
||||
let community = extract_community_from_cc(activity, context).await?;
|
||||
verify_mod_activity(activity, announce.to_owned(), &community, context).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn verify_undo_remove_actor_instance<T, Kind>(
|
||||
undo: &Undo,
|
||||
inner: &T,
|
||||
|
|
Loading…
Reference in a new issue