Remove ActivityFields trait, deserialize into another struct instead

refactor-apub-2
Felix Ableitner 3 years ago
parent 969a7f2d1b
commit bd3352423a

@ -1,18 +1,3 @@
use activitystreams::public;
use lemmy_api_common::{blocking, check_post_deleted_or_removed};
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType, ApubObject},
verify::verify_domains_match,
};
use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
use crate::{
activities::{
check_community_deleted_or_removed,
@ -28,6 +13,19 @@ use crate::{
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson},
protocol::activities::{create_or_update::comment::CreateOrUpdateComment, CreateOrUpdateType},
};
use activitystreams::public;
use lemmy_api_common::{blocking, check_post_deleted_or_removed};
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType, ApubObject},
verify::verify_domains_match,
};
use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
impl CreateOrUpdateComment {
pub async fn send(
@ -81,7 +79,7 @@ impl ActivityHandler for CreateOrUpdateComment {
let post = self.object.get_parents(context, request_counter).await?.0;
let community = self.get_community(context, request_counter).await?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
check_community_deleted_or_removed(&community)?;

@ -65,7 +65,7 @@ impl ActivityHandler for AddMod {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_mod_action(&self.actor, &community, context, request_counter).await?;

@ -2,7 +2,7 @@ use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_is_public},
activity_lists::AnnouncableActivities,
fetcher::object_id::ObjectId,
http::is_activity_already_known,
http::{is_activity_already_known, ActivityCommonFields},
insert_activity,
objects::community::ApubCommunity,
protocol::activities::community::announce::AnnounceActivity,
@ -10,7 +10,7 @@ use crate::{
use activitystreams::{activity::kind::AnnounceType, public};
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
traits::{ActivityHandler, ActorType},
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
@ -60,7 +60,7 @@ impl ActivityHandler for AnnounceActivity {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
self.object.verify(context, request_counter).await?;
Ok(())
}
@ -70,11 +70,15 @@ impl ActivityHandler for AnnounceActivity {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
if is_activity_already_known(context.pool(), self.object.id_unchecked()).await? {
// TODO: this is pretty ugly, but i cant think of a much better way
let object = serde_json::to_string(&self.object)?;
let object_data: ActivityCommonFields = serde_json::from_str(&object)?;
if is_activity_already_known(context.pool(), &object_data.id).await? {
return Ok(());
}
insert_activity(
self.object.id_unchecked(),
&object_data.id,
self.object.clone(),
false,
true,

@ -76,7 +76,7 @@ impl ActivityHandler for BlockUserFromCommunity {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_mod_action(&self.actor, &community, context, request_counter).await?;

@ -64,7 +64,7 @@ impl ActivityHandler for RemoveMod {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_mod_action(&self.actor, &community, context, request_counter).await?;

@ -1,5 +1,16 @@
use crate::{
activities::{
generate_activity_id,
send_lemmy_activity,
verify_activity,
verify_person_in_community,
},
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::community::report::Report,
PostOrComment,
};
use activitystreams::activity::kind::FlagType;
use lemmy_api_common::{blocking, comment::CommentReportResponse, post::PostReportResponse};
use lemmy_apub_lib::{
data::Data,
@ -16,19 +27,6 @@ use lemmy_db_views::{comment_report_view::CommentReportView, post_report_view::P
use lemmy_utils::LemmyError;
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
use crate::{
activities::{
generate_activity_id,
send_lemmy_activity,
verify_activity,
verify_person_in_community,
},
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::community::report::Report,
PostOrComment,
};
impl Report {
pub async fn send(
object_id: ObjectId<PostOrComment>,
@ -72,7 +70,7 @@ impl ActivityHandler for Report {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.to[0].dereference(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
Ok(())

@ -66,7 +66,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_mod_action(&self.actor, &community, context, request_counter).await?;

@ -59,7 +59,7 @@ impl ActivityHandler for UpdateCommunity {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_mod_action(&self.actor, &community, context, request_counter).await?;

@ -1,7 +1,22 @@
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
deletion::{
receive_delete_action,
verify_delete_activity,
DeletableObjects,
},
generate_activity_id,
verify_activity,
verify_is_public,
},
activity_lists::AnnouncableActivities,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::deletion::delete::Delete,
};
use activitystreams::{activity::kind::DeleteType, public};
use anyhow::anyhow;
use url::Url;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
@ -29,20 +44,7 @@ use lemmy_websocket::{
LemmyContext,
UserOperationCrud,
};
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
generate_activity_id,
verify_activity,
verify_is_public,
},
activity_lists::AnnouncableActivities,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::deletion::delete::Delete,
};
use url::Url;
#[async_trait::async_trait(?Send)]
impl ActivityHandler for Delete {
@ -53,11 +55,11 @@ impl ActivityHandler for Delete {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_delete_activity(
&self.object,
self,
&self.actor,
&community,
self.summary.is_some(),
context,

@ -1,8 +1,12 @@
use url::Url;
use crate::{
activities::{verify_mod_action, verify_person_in_community},
fetcher::object_id::ObjectId,
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
traits::{ActivityFields, ActorType, ApubObject},
traits::{ActorType, ApubObject},
verify::verify_domains_match,
};
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
@ -12,13 +16,7 @@ use lemmy_websocket::{
LemmyContext,
UserOperationCrud,
};
use crate::{
activities::{verify_mod_action, verify_person_in_community},
fetcher::object_id::ObjectId,
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use url::Url;
pub mod delete;
pub mod undo_delete;
@ -80,27 +78,26 @@ impl DeletableObjects {
pub(in crate::activities) async fn verify_delete_activity(
object: &Url,
activity: &dyn ActivityFields,
actor: &ObjectId<ApubPerson>,
community: &ApubCommunity,
is_mod_action: bool,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object = DeletableObjects::read_from_db(object, context).await?;
let actor = ObjectId::new(activity.actor().clone());
match object {
DeletableObjects::Community(community) => {
if community.local {
// can only do this check for local community, in remote case it would try to fetch the
// deleted community (which fails)
verify_person_in_community(&actor, &community, context, request_counter).await?;
verify_person_in_community(actor, &community, context, request_counter).await?;
}
// community deletion is always a mod (or admin) action
verify_mod_action(&actor, &community, context, request_counter).await?;
verify_mod_action(actor, &community, context, request_counter).await?;
}
DeletableObjects::Post(p) => {
verify_delete_activity_post_or_comment(
activity,
actor,
&p.ap_id.clone().into(),
community,
is_mod_action,
@ -111,7 +108,7 @@ pub(in crate::activities) async fn verify_delete_activity(
}
DeletableObjects::Comment(c) => {
verify_delete_activity_post_or_comment(
activity,
actor,
&c.ap_id.clone().into(),
community,
is_mod_action,
@ -125,20 +122,19 @@ pub(in crate::activities) async fn verify_delete_activity(
}
async fn verify_delete_activity_post_or_comment(
activity: &dyn ActivityFields,
actor: &ObjectId<ApubPerson>,
object_id: &Url,
community: &ApubCommunity,
is_mod_action: bool,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let actor = ObjectId::new(activity.actor().clone());
verify_person_in_community(&actor, community, context, request_counter).await?;
verify_person_in_community(actor, community, context, request_counter).await?;
if is_mod_action {
verify_mod_action(&actor, community, context, request_counter).await?;
verify_mod_action(actor, community, context, request_counter).await?;
} else {
// domain of post ap_id and post.creator ap_id are identical, so we just check the former
verify_domains_match(activity.actor(), object_id)?;
verify_domains_match(actor.inner(), object_id)?;
}
Ok(())
}

@ -1,7 +1,18 @@
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
generate_activity_id,
verify_activity,
verify_is_public,
},
activity_lists::AnnouncableActivities,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use activitystreams::{activity::kind::UndoType, public};
use anyhow::anyhow;
use url::Url;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
@ -14,20 +25,7 @@ use lemmy_websocket::{
LemmyContext,
UserOperationCrud,
};
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
generate_activity_id,
verify_activity,
verify_is_public,
},
activity_lists::AnnouncableActivities,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use url::Url;
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDelete {
@ -38,12 +36,12 @@ impl ActivityHandler for UndoDelete {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
self.object.verify(context, request_counter).await?;
let community = self.get_community(context, request_counter).await?;
verify_delete_activity(
&self.object.object,
self,
&self.actor,
&community,
self.object.summary.is_some(),
context,

@ -7,7 +7,7 @@ use activitystreams::activity::kind::AcceptType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
traits::{ActivityHandler, ActorType},
verify::verify_urls_match,
};
use lemmy_db_schema::{source::community::CommunityFollower, traits::Followable};
@ -51,9 +51,9 @@ impl ActivityHandler for AcceptFollowCommunity {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_urls_match(self.to[0].inner(), self.object.actor())?;
verify_urls_match(self.actor(), self.object.to[0].inner())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_urls_match(self.to[0].inner(), self.object.actor.inner())?;
verify_urls_match(self.actor.inner(), self.object.to[0].inner())?;
self.object.verify(context, request_counter).await?;
Ok(())
}

@ -71,7 +71,7 @@ impl ActivityHandler for FollowCommunity {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_urls_match(self.to[0].inner(), self.object.inner())?;
verify_person(&self.actor, context, request_counter).await?;
let community = self.to[0].dereference(context, request_counter).await?;

@ -8,7 +8,7 @@ use activitystreams::activity::kind::UndoType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
traits::{ActivityHandler, ActorType},
verify::verify_urls_match,
};
use lemmy_db_schema::{
@ -49,9 +49,9 @@ impl ActivityHandler for UndoFollowCommunity {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_urls_match(self.to[0].inner(), self.object.object.inner())?;
verify_urls_match(self.actor(), self.object.actor())?;
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
verify_person(&self.actor, context, request_counter).await?;
self.object.verify(context, request_counter).await?;
Ok(())

@ -11,7 +11,7 @@ use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
activity_queue::send_activity,
traits::{ActivityFields, ActorType},
traits::ActorType,
verify::verify_domains_match,
};
use lemmy_db_schema::source::community::Community;
@ -71,9 +71,9 @@ pub(crate) async fn verify_person_in_community(
Ok(())
}
fn verify_activity(activity: &dyn ActivityFields, settings: &Settings) -> Result<(), LemmyError> {
check_is_apub_id_valid(activity.actor(), false, settings)?;
verify_domains_match(activity.id_unchecked(), activity.actor())?;
fn verify_activity(id: &Url, actor: &Url, settings: &Settings) -> Result<(), LemmyError> {
check_is_apub_id_valid(actor, false, settings)?;
verify_domains_match(id, actor)?;
Ok(())
}

@ -1,16 +1,3 @@
use activitystreams::public;
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType, ApubObject},
verify::{verify_domains_match, verify_urls_match},
};
use lemmy_db_schema::{source::community::Community, traits::Crud};
use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
use crate::{
activities::{
check_community_deleted_or_removed,
@ -26,6 +13,17 @@ use crate::{
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType},
};
use activitystreams::public;
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType, ApubObject},
verify::{verify_domains_match, verify_urls_match},
};
use lemmy_db_schema::{source::community::Community, traits::Crud};
use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
impl CreateOrUpdatePost {
pub(crate) async fn new(
@ -77,7 +75,7 @@ impl ActivityHandler for CreateOrUpdatePost {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
check_community_deleted_or_removed(&community)?;
@ -85,7 +83,7 @@ impl ActivityHandler for CreateOrUpdatePost {
match self.kind {
CreateOrUpdateType::Create => {
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
verify_urls_match(self.actor(), self.object.attributed_to.inner())?;
verify_urls_match(self.actor.inner(), self.object.attributed_to.inner())?;
// Check that the post isnt locked or stickied, as that isnt possible for newly created posts.
// However, when fetching a remote post we generate a new create activity with the current
// locked/stickied value, so this check may fail. So only check if its a local community,
@ -102,7 +100,7 @@ impl ActivityHandler for CreateOrUpdatePost {
verify_mod_action(&self.actor, &community, context, request_counter).await?;
} else {
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
verify_urls_match(self.actor(), self.object.attributed_to.inner())?;
verify_urls_match(self.actor.inner(), self.object.attributed_to.inner())?;
}
}
}

@ -54,7 +54,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
self.object.verify(context, request_counter).await?;

@ -62,7 +62,7 @@ impl ActivityHandler for DeletePrivateMessage {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.inner())?;
Ok(())

@ -11,7 +11,7 @@ use activitystreams::activity::kind::UndoType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
traits::{ActivityHandler, ActorType},
verify::{verify_domains_match, verify_urls_match},
};
use lemmy_db_schema::{
@ -59,10 +59,10 @@ impl ActivityHandler for UndoDeletePrivateMessage {
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_urls_match(self.actor(), self.object.actor())?;
verify_domains_match(self.actor(), self.object.object.inner())?;
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
verify_domains_match(self.actor.inner(), self.object.object.inner())?;
self.object.verify(context, request_counter).await?;
Ok(())
}

@ -1,17 +1,3 @@
use std::ops::Deref;
use activitystreams::{activity::kind::UndoType, public};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
verify::verify_urls_match,
};
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
@ -30,6 +16,17 @@ use crate::{
},
PostOrComment,
};
use activitystreams::{activity::kind::UndoType, public};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType},
verify::verify_urls_match,
};
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use std::ops::Deref;
impl UndoVote {
pub async fn send(
@ -73,10 +70,10 @@ impl ActivityHandler for UndoVote {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_urls_match(self.actor(), self.object.actor())?;
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
self.object.verify(context, request_counter).await?;
Ok(())
}

@ -1,20 +1,3 @@
use std::ops::Deref;
use activitystreams::public;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType},
};
use lemmy_db_schema::{
newtypes::CommunityId,
source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use crate::{
activities::{
community::{announce::GetCommunity, send_to_community},
@ -30,6 +13,20 @@ use crate::{
protocol::activities::voting::vote::{Vote, VoteType},
PostOrComment,
};
use activitystreams::public;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ActorType},
};
use lemmy_db_schema::{
newtypes::CommunityId,
source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use std::ops::Deref;
impl Vote {
pub(in crate::activities::voting) fn new(
@ -79,7 +76,7 @@ impl ActivityHandler for Vote {
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
Ok(())

@ -26,12 +26,12 @@ use crate::{
voting::{undo_vote::UndoVote, vote::Vote},
},
};
use lemmy_apub_lib::traits::{ActivityFields, ActivityHandler};
use lemmy_apub_lib::traits::ActivityHandler;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
#[activity_handler(LemmyContext)]
pub enum SharedInboxActivities {
@ -41,7 +41,7 @@ pub enum SharedInboxActivities {
PersonInboxActivities(PersonInboxActivities),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
#[activity_handler(LemmyContext)]
pub enum GroupInboxActivities {
@ -51,7 +51,7 @@ pub enum GroupInboxActivities {
Report(Report),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
#[activity_handler(LemmyContext)]
pub enum PersonInboxActivities {
@ -64,7 +64,7 @@ pub enum PersonInboxActivities {
AnnounceActivity(Box<AnnounceActivity>),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
#[activity_handler(LemmyContext)]
pub enum AnnouncableActivities {

@ -1,44 +1,14 @@
pub mod object_id;
pub mod post_or_comment;
pub mod search;
pub mod user_or_community;
use crate::{
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
};
use chrono::NaiveDateTime;
use lemmy_apub_lib::traits::ActorType;
use lemmy_db_schema::naive_now;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
static ACTOR_REFETCH_INTERVAL_SECONDS: i64 = 24 * 60 * 60;
static ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG: i64 = 10;
/// Get a remote actor from its apub ID (either a person or a community). Thin wrapper around
/// `get_or_fetch_and_upsert_person()` and `get_or_fetch_and_upsert_community()`.
///
/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
/// Otherwise it is fetched from the remote instance, stored and returned.
pub(crate) async fn get_or_fetch_and_upsert_actor(
apub_id: Url,
context: &LemmyContext,
recursion_counter: &mut i32,
) -> Result<Box<dyn ActorType>, LemmyError> {
let community_id = ObjectId::<ApubCommunity>::new(apub_id.clone());
let community = community_id.dereference(context, recursion_counter).await;
let actor: Box<dyn ActorType> = match community {
Ok(c) => Box::new(c),
Err(_) => {
let person_id = ObjectId::new(apub_id);
let person: ApubPerson = person_id.dereference(context, recursion_counter).await?;
Box::new(person)
}
};
Ok(actor)
}
/// Determines when a remote actor should be refetched from its instance. In release builds, this is
/// `ACTOR_REFETCH_INTERVAL_SECONDS` after the last refetch, in debug builds
/// `ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG`.

@ -1,16 +1,13 @@
use chrono::NaiveDateTime;
use serde::Deserialize;
use url::Url;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::source::{comment::CommentForm, post::PostForm};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use crate::{
objects::{comment::ApubComment, post::ApubPost},
protocol::objects::{note::Note, page::Page},
};
use chrono::NaiveDateTime;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
use url::Url;
#[derive(Clone, Debug)]
pub enum PostOrComment {
@ -18,11 +15,6 @@ pub enum PostOrComment {
Comment(ApubComment),
}
pub enum PostOrCommentForm {
PostForm(Box<PostForm>),
CommentForm(CommentForm),
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum PageOrNote {
@ -44,10 +36,7 @@ impl ApubObject for PostOrComment {
async fn read_from_apub_id(
object_id: Url,
data: &Self::DataType,
) -> Result<Option<Self>, LemmyError>
where
Self: Sized,
{
) -> Result<Option<Self>, LemmyError> {
let post = ApubPost::read_from_apub_id(object_id.clone(), data).await?;
Ok(match post {
Some(o) => Some(PostOrComment::Post(Box::new(o))),
@ -77,10 +66,7 @@ impl ApubObject for PostOrComment {
context: &LemmyContext,
expected_domain: &Url,
request_counter: &mut i32,
) -> Result<Self, LemmyError>
where
Self: Sized,
{
) -> Result<Self, LemmyError> {
Ok(match apub {
PageOrNote::Page(p) => PostOrComment::Post(Box::new(
ApubPost::from_apub(p, context, expected_domain, request_counter).await?,

@ -0,0 +1,113 @@
use crate::{
objects::{community::ApubCommunity, person::ApubPerson},
protocol::objects::{group::Group, person::Person},
};
use activitystreams::{chrono::NaiveDateTime, url::Url};
use lemmy_apub_lib::traits::{ActorType, ApubObject};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
#[derive(Clone, Debug)]
pub enum UserOrCommunity {
User(ApubPerson),
Community(ApubCommunity),
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum PersonOrGroup {
Person(Person),
Group(Group),
}
#[async_trait::async_trait(?Send)]
impl ApubObject for UserOrCommunity {
type DataType = LemmyContext;
type ApubType = PersonOrGroup;
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
Some(match self {
UserOrCommunity::User(p) => p.last_refreshed_at,
UserOrCommunity::Community(p) => p.last_refreshed_at,
})
}
async fn read_from_apub_id(
object_id: Url,
data: &Self::DataType,
) -> Result<Option<Self>, LemmyError> {
let person = ApubPerson::read_from_apub_id(object_id.clone(), data).await?;
Ok(match person {
Some(o) => Some(UserOrCommunity::User(o)),
None => ApubCommunity::read_from_apub_id(object_id, data)
.await?
.map(UserOrCommunity::Community),
})
}
async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
match self {
UserOrCommunity::User(p) => p.delete(data).await,
UserOrCommunity::Community(p) => p.delete(data).await,
}
}
async fn to_apub(&self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
unimplemented!()
}
fn to_tombstone(&self) -> Result<Self::TombstoneType, LemmyError> {
unimplemented!()
}
async fn from_apub(
apub: &Self::ApubType,
data: &Self::DataType,
expected_domain: &Url,
request_counter: &mut i32,
) -> Result<Self, LemmyError> {
Ok(match apub {
PersonOrGroup::Person(p) => UserOrCommunity::User(
ApubPerson::from_apub(p, data, expected_domain, request_counter).await?,
),
PersonOrGroup::Group(p) => UserOrCommunity::Community(
ApubCommunity::from_apub(p, data, expected_domain, request_counter).await?,
),
})
}
}
impl ActorType for UserOrCommunity {
fn is_local(&self) -> bool {
todo!()
}
fn actor_id(&self) -> Url {
todo!()
}
fn name(&self) -> String {
todo!()
}
fn public_key(&self) -> Option<String> {
match self {
UserOrCommunity::User(p) => p.public_key(),
UserOrCommunity::Community(p) => p.public_key(),
}
}
fn private_key(&self) -> Option<String> {
todo!()
}
fn inbox_url(&self) -> Url {
todo!()
}
fn shared_inbox_url(&self) -> Option<Url> {
todo!()
}
}

@ -14,6 +14,7 @@ use crate::{
create_apub_tombstone_response,
payload_to_string,
receive_activity,
ActivityCommonFields,
},
objects::community::ApubCommunity,
protocol::{
@ -23,7 +24,7 @@ use crate::{
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
use lemmy_apub_lib::traits::{ActivityFields, ApubObject};
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
@ -64,23 +65,25 @@ pub async fn community_inbox(
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received community inbox activity {}", unparsed);
let activity_data: ActivityCommonFields = serde_json::from_str(&unparsed)?;
let activity = serde_json::from_str::<WithContext<GroupInboxActivities>>(&unparsed)?;
receive_group_inbox(activity.inner(), request, &context).await?;
receive_group_inbox(activity.inner(), activity_data, request, &context).await?;
Ok(HttpResponse::Ok().finish())
}
pub(in crate::http) async fn receive_group_inbox(
activity: GroupInboxActivities,
activity_data: ActivityCommonFields,
request: HttpRequest,
context: &LemmyContext,
) -> Result<HttpResponse, LemmyError> {
let res = receive_activity(request, activity.clone(), context).await;
let actor_id = ObjectId::new(activity_data.actor.clone());
let res = receive_activity(request, activity.clone(), activity_data, context).await;
if let GroupInboxActivities::AnnouncableActivities(announcable) = activity {
let community = announcable.get_community(context, &mut 0).await?;
let actor_id = ObjectId::new(announcable.actor().clone());
verify_person_in_community(&actor_id, &community, context, &mut 0).await?;
if community.local {
AnnounceActivity::send(announcable, &community, vec![], context).await?;

@ -2,7 +2,7 @@ use crate::{
activity_lists::SharedInboxActivities,
check_is_apub_id_valid,
context::WithContext,
fetcher::get_or_fetch_and_upsert_actor,
fetcher::{object_id::ObjectId, user_or_community::UserOrCommunity},
http::{community::receive_group_inbox, person::receive_person_inbox},
insert_activity,
};
@ -20,7 +20,7 @@ use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
signatures::verify_signature,
traits::{ActivityFields, ActivityHandler},
traits::{ActivityHandler, ActorType},
APUB_JSON_CONTENT_TYPE,
};
use lemmy_db_schema::{source::activity::Activity, DbPool};
@ -44,13 +44,14 @@ pub async fn shared_inbox(
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received shared inbox activity {}", unparsed);
let activity_data: ActivityCommonFields = serde_json::from_str(&unparsed)?;
let activity = serde_json::from_str::<WithContext<SharedInboxActivities>>(&unparsed)?;
match activity.inner() {
SharedInboxActivities::GroupInboxActivities(g) => {
receive_group_inbox(g, request, &context).await
receive_group_inbox(g, activity_data, request, &context).await
}
SharedInboxActivities::PersonInboxActivities(p) => {
receive_person_inbox(p, request, &context).await
receive_person_inbox(p, activity_data, request, &context).await
}
}
}
@ -65,15 +66,22 @@ async fn payload_to_string(mut payload: Payload) -> Result<String, LemmyError> {
Ok(unparsed)
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ActivityCommonFields {
pub(crate) id: Url,
pub(crate) actor: Url,
}
// TODO: move most of this code to library
async fn receive_activity<'a, T>(
request: HttpRequest,
activity: T,
activity_data: ActivityCommonFields,
context: &LemmyContext,
) -> Result<HttpResponse, LemmyError>
where
T: ActivityHandler<DataType = LemmyContext>
+ ActivityFields
+ Clone
+ Deserialize<'a>
+ Serialize
@ -81,26 +89,27 @@ where
+ Send
+ 'static,
{
check_is_apub_id_valid(&activity_data.actor, false, &context.settings())?;
let request_counter = &mut 0;
let actor =
get_or_fetch_and_upsert_actor(activity.actor().clone(), context, request_counter).await?;
let actor = ObjectId::<UserOrCommunity>::new(activity_data.actor)
.dereference(context, request_counter)
.await?;
verify_signature(&request, &actor.public_key().context(location_info!())?)?;
// Do nothing if we received the same activity before
if is_activity_already_known(context.pool(), activity.id_unchecked()).await? {
if is_activity_already_known(context.pool(), &activity_data.id).await? {
return Ok(HttpResponse::Ok().finish());
}
check_is_apub_id_valid(activity.actor(), false, &context.settings())?;
info!("Verifying activity {}", activity.id_unchecked().to_string());
info!("Verifying activity {}", activity_data.id.to_string());
activity
.verify(&Data::new(context.clone()), request_counter)
.await?;
assert_activity_not_local(&activity, &context.settings().hostname)?;
assert_activity_not_local(&activity_data.id, &context.settings().hostname)?;
// Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen
// if we receive the same activity twice in very quick succession.
insert_activity(
activity.id_unchecked(),
&activity_data.id,
activity.clone(),
false,
true,
@ -108,7 +117,7 @@ where
)
.await?;
info!("Receiving activity {}", activity.id_unchecked().to_string());
info!("Receiving activity {}", activity_data.id.to_string());
activity
.receive(&Data::new(context.clone()), request_counter)
.await?;
@ -183,17 +192,14 @@ pub(crate) async fn is_activity_already_known(
}
}
fn assert_activity_not_local<T: Debug + ActivityFields>(
activity: &T,
hostname: &str,
) -> Result<(), LemmyError> {
let activity_domain = activity.id_unchecked().domain().context(location_info!())?;
fn assert_activity_not_local(id: &Url, hostname: &str) -> Result<(), LemmyError> {
let activity_domain = id.domain().context(location_info!())?;
if activity_domain == hostname {
return Err(
anyhow!(
"Error: received activity which was sent by local instance: {:?}",
activity
id
)
.into(),
);

@ -6,6 +6,7 @@ use crate::{
create_apub_tombstone_response,
payload_to_string,
receive_activity,
ActivityCommonFields,
},
objects::person::ApubPerson,
protocol::collections::person_outbox::PersonOutbox,
@ -54,16 +55,18 @@ pub async fn person_inbox(
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received person inbox activity {}", unparsed);
let activity_data: ActivityCommonFields = serde_json::from_str(&unparsed)?;
let activity = serde_json::from_str::<WithContext<PersonInboxActivities>>(&unparsed)?;
receive_person_inbox(activity.inner(), request, &context).await
receive_person_inbox(activity.inner(), activity_data, request, &context).await
}
pub(in crate::http) async fn receive_person_inbox(
activity: PersonInboxActivities,
activity_data: ActivityCommonFields,
request: HttpRequest,
context: &LemmyContext,
) -> Result<HttpResponse, LemmyError> {
receive_activity(request, activity, context).await
receive_activity(request, activity, activity_data, context).await
}
pub(crate) async fn get_apub_person_outbox(

@ -1,10 +1,9 @@
use crate::{fetcher::object_id::ObjectId, objects::person::ApubPerson};
use activitystreams::{activity::kind::AddType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AddMod {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
objects::community::ApubCommunity,
};
use activitystreams::{activity::kind::AnnounceType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AnnounceActivity {
pub(crate) actor: ObjectId<ApubCommunity>,

@ -3,11 +3,10 @@ use crate::{
objects::{community::ApubCommunity, person::ApubPerson},
};
use activitystreams::{activity::kind::BlockType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockUserFromCommunity {
pub(crate) actor: ObjectId<ApubPerson>,

@ -1,10 +1,9 @@
use crate::{fetcher::object_id::ObjectId, objects::person::ApubPerson};
use activitystreams::{activity::kind::RemoveType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoveMod {
pub(crate) actor: ObjectId<ApubPerson>,

@ -3,11 +3,10 @@ use crate::{
objects::{community::ApubCommunity, person::ApubPerson},
};
use activitystreams::{activity::kind::FlagType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Report {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::activities::community::block_user::BlockUserFromCommunity,
};
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoBlockUserFromCommunity {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,13 +4,12 @@ use crate::{
protocol::objects::group::Group,
};
use activitystreams::{activity::kind::UpdateType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
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, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateCommunity {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::{activities::CreateOrUpdateType, objects::note::Note},
};
use activitystreams::{link::Mention, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrUpdateComment {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::{activities::CreateOrUpdateType, objects::page::Page},
};
use activitystreams::unparsed::Unparsed;
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrUpdatePost {
pub(crate) actor: ObjectId<ApubPerson>,

@ -1,12 +1,11 @@
use crate::{fetcher::object_id::ObjectId, objects::person::ApubPerson};
use activitystreams::{activity::kind::DeleteType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use url::Url;
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Delete {
pub(crate) actor: ObjectId<ApubPerson>,

@ -1,16 +1,13 @@
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use serde::{Deserialize, Serialize};
use url::Url;
use lemmy_apub_lib::traits::ActivityFields;
use crate::{
fetcher::object_id::ObjectId,
objects::person::ApubPerson,
protocol::activities::deletion::delete::Delete,
};
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoDelete {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::activities::following::follow::FollowCommunity,
};
use activitystreams::{activity::kind::AcceptType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AcceptFollowCommunity {
pub(crate) actor: ObjectId<ApubCommunity>,

@ -3,11 +3,10 @@ use crate::{
objects::{community::ApubCommunity, person::ApubPerson},
};
use activitystreams::{activity::kind::FollowType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FollowCommunity {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::activities::following::follow::FollowCommunity,
};
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoFollowCommunity {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage},
};
use activitystreams::unparsed::Unparsed;
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrUpdatePrivateMessage {
pub(crate) id: Url,

@ -3,11 +3,10 @@ use crate::{
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
};
use activitystreams::{activity::kind::DeleteType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DeletePrivateMessage {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,11 +4,10 @@ use crate::{
protocol::activities::private_message::delete::DeletePrivateMessage,
};
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use lemmy_apub_lib::traits::ActivityFields;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoDeletePrivateMessage {
pub(crate) actor: ObjectId<ApubPerson>,

@ -1,16 +1,13 @@
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use serde::{Deserialize, Serialize};
use url::Url;
use lemmy_apub_lib::traits::ActivityFields;
use crate::{
fetcher::object_id::ObjectId,
objects::person::ApubPerson,
protocol::activities::voting::vote::Vote,
};
use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoVote {
pub(crate) actor: ObjectId<ApubPerson>,

@ -4,14 +4,13 @@ use crate::{
};
use activitystreams::unparsed::Unparsed;
use anyhow::anyhow;
use lemmy_apub_lib::traits::ActivityFields;
use lemmy_utils::LemmyError;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use strum_macros::ToString;
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Vote {
pub(crate) actor: ObjectId<ApubPerson>,

@ -5,11 +5,6 @@ pub use lemmy_apub_lib_derive::*;
use lemmy_utils::{location_info, LemmyError};
use url::Url;
pub trait ActivityFields {
fn id_unchecked(&self) -> &Url;
fn actor(&self) -> &Url;
}
#[async_trait::async_trait(?Send)]
pub trait ActivityHandler {
type DataType;

@ -127,40 +127,3 @@ fn generate_match_arm(enum_name: &Ident, variant: &Variant, body: &TokenStream)
_ => unimplemented!(),
}
}
#[proc_macro_derive(ActivityFields)]
pub fn derive_activity_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let expanded = match input.data {
Data::Enum(e) => {
let variants = e.variants;
let impl_id = variants
.iter()
.map(|v| generate_match_arm(&name, v, &quote! {a.id_unchecked()}));
let impl_actor = variants
.iter()
.map(|v| generate_match_arm(&name, v, &quote! {a.actor()}));
quote! {
impl #impl_generics lemmy_apub_lib::traits::ActivityFields for #name #ty_generics #where_clause {
fn id_unchecked(&self) -> &url::Url { match self { #(#impl_id)* } }
fn actor(&self) -> &url::Url { match self { #(#impl_actor)* } }
}
}
}
Data::Struct(_) => {
quote! {
impl #impl_generics lemmy_apub_lib::traits::ActivityFields for #name #ty_generics #where_clause {
fn id_unchecked(&self) -> &url::Url { &self.id }
fn actor(&self) -> &url::Url { &self.actor.inner() }
}
}
}
_ => unimplemented!(),
};
expanded.into()
}

Loading…
Cancel
Save