activities::{
check_community_deleted_or_removed,
comment::{collect_non_local_mentions, get_notif_recipients},
- community::{announce::AnnouncableActivities, send_to_community},
- extract_community,
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
- let community = extract_community(&self.cc, context, request_counter).await?;
- let community_id = ObjectId::new(community.actor_id());
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_person_in_community(&self.actor, &community_id, context, request_counter).await?;
+ verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
check_community_deleted_or_removed(&community)?;
check_post_deleted_or_removed(&post)?;
}
}
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for CreateOrUpdateComment {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ let post = self.object.get_parents(context, request_counter).await?.0;
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, post.community_id)
+ })
+ .await??;
+ Ok(community.into())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ get_community_from_moderators_url,
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_add_remove_moderator_target,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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, &self.cc[0], context, request_counter).await?;
verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
Ok(())
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = self.cc[0].dereference(context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
let new_mod = self.object.dereference(context, request_counter).await?;
// If we had to refetch the community while parsing the activity, then the new mod has already
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for AddMod {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ get_community_from_moderators_url(&self.target, context, request_counter).await
+ }
+}
generate_activity_id,
post::create_or_update::CreateOrUpdatePost,
verify_activity,
- verify_community,
verify_is_public,
voting::{undo_vote::UndoVote, vote::Vote},
},
insert_activity,
objects::community::ApubCommunity,
send_lemmy_activity,
- CommunityType,
};
use activitystreams::{
activity::kind::AnnounceType,
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
+ verify::verify_urls_match,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
RemoveMod(RemoveMod),
}
+#[async_trait::async_trait(?Send)]
+pub(crate) trait GetCommunity {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError>;
+}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for AnnouncableActivities {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ use AnnouncableActivities::*;
+ let community = match self {
+ CreateOrUpdateComment(a) => a.get_community(context, request_counter).await?,
+ CreateOrUpdatePost(a) => a.get_community(context, request_counter).await?,
+ Vote(a) => a.get_community(context, request_counter).await?,
+ UndoVote(a) => a.get_community(context, request_counter).await?,
+ Delete(a) => a.get_community(context, request_counter).await?,
+ UndoDelete(a) => a.get_community(context, request_counter).await?,
+ UpdateCommunity(a) => a.get_community(context, request_counter).await?,
+ BlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
+ UndoBlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
+ AddMod(a) => a.get_community(context, request_counter).await?,
+ RemoveMod(a) => a.get_community(context, request_counter).await?,
+ };
+ verify_urls_match(self.actor(), &community.actor_id())?;
+ Ok(community)
+ }
+}
+
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[serde(rename_all = "camelCase")]
pub struct AnnounceActivity {
actor: ObjectId::new(community.actor_id()),
to: vec![public()],
object,
- cc: vec![community.followers_url()],
+ cc: vec![community.followers_url.clone().into_inner()],
kind: AnnounceType::Announce,
id: generate_activity_id(
&AnnounceType::Announce,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_community(&self.actor, context, request_counter).await?;
self.object.verify(context, request_counter).await?;
Ok(())
}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
to: Vec<Url>,
pub(in crate::activities::community) object: ObjectId<ApubPerson>,
cc: [ObjectId<ApubCommunity>; 1],
+ target: ObjectId<ApubCommunity>,
#[serde(rename = "type")]
kind: BlockType,
id: Url,
to: vec![public()],
object: ObjectId::new(target.actor_id()),
cc: [ObjectId::new(community.actor_id())],
+ target: ObjectId::new(community.actor_id()),
kind: BlockType::Block,
id: generate_activity_id(
BlockType::Block,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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, &self.cc[0], context, request_counter).await?;
Ok(())
}
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = self.cc[0].dereference(context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
let blocked_user = self.object.dereference(context, request_counter).await?;
let community_user_ban_form = CommunityPersonBanForm {
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for BlockUserFromCommunity {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ self.target.dereference(context, request_counter).await
+ }
+}
use crate::{
activities::community::announce::{AnnouncableActivities, AnnounceActivity},
check_is_apub_id_valid,
+ fetcher::object_id::ObjectId,
insert_activity,
objects::community::ApubCommunity,
send_lemmy_activity,
- CommunityType,
};
use itertools::Itertools;
use lemmy_apub_lib::traits::ActorType;
Ok(())
}
+
+async fn get_community_from_moderators_url(
+ moderators: &Url,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+) -> Result<ApubCommunity, LemmyError> {
+ let community_id = Url::parse(&moderators.to_string().replace("/moderators", ""))?;
+ ObjectId::new(community_id)
+ .dereference(context, request_counter)
+ .await
+}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ get_community_from_moderators_url,
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_add_remove_moderator_target,
cc: [ObjectId<ApubCommunity>; 1],
#[serde(rename = "type")]
kind: RemoveType,
- // if target is set, this is means remove mod from community
pub(in crate::activities) target: Url,
id: Url,
#[serde(rename = "@context")]
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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, &self.cc[0], context, request_counter).await?;
verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
Ok(())
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = self.cc[0].dereference(context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
let remove_mod = self.object.dereference(context, request_counter).await?;
let form = CommunityModeratorForm {
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for RemoveMod {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ get_community_from_moderators_url(&self.target, context, request_counter).await
+ }
+}
use crate::{
activities::{
community::{
- announce::AnnouncableActivities,
+ announce::{AnnouncableActivities, GetCommunity},
block_user::BlockUserFromCommunity,
send_to_community,
},
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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, &self.cc[0], context, request_counter).await?;
self.object.verify(context, request_counter).await?;
Ok(())
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = self.cc[0].dereference(context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
let blocked_user = self
.object
.object
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for UndoBlockUserFromCommunity {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ self.object.get_community(context, request_counter).await
+ }
+}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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, &self.cc[0], context, request_counter).await?;
Ok(())
}
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let cc = self.cc[0].clone();
- let community = cc.dereference(context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
let updated_community = Group::from_apub_to_form(
&self.object,
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for UpdateCommunity {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ let cid = ObjectId::new(self.object.id.clone());
+ cid.dereference(context, request_counter).await
+ }
+}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
deletion::{
receive_delete_action,
verify_delete_activity,
}
Ok(())
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for Delete {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ _request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ let community_id = match DeletableObjects::read_from_db(&self.object, context).await? {
+ DeletableObjects::Community(c) => c.id,
+ DeletableObjects::Comment(c) => {
+ let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??;
+ post.community_id
+ }
+ DeletableObjects::Post(p) => p.community_id,
+ };
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, community_id)
+ })
+ .await??;
+ Ok(community.into())
+ }
+}
if c.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_id, context, request_counter).await?;
+ verify_person_in_community(&actor, &c, context, request_counter).await?;
}
// community deletion is always a mod (or admin) action
verify_mod_action(
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let actor = ObjectId::new(activity.actor().clone());
- verify_person_in_community(&actor, community_id, context, request_counter).await?;
+ let community = community_id.dereference(context, request_counter).await?;
+ verify_person_in_community(&actor, &community, context, request_counter).await?;
if is_mod_action {
verify_mod_action(&actor, community_id, context, request_counter).await?;
} else {
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
deletion::{
delete::Delete,
receive_delete_action,
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for UndoDelete {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ self.object.get_community(context, request_counter).await
+ }
+}
use crate::{
- activities::{
- following::follow::FollowCommunity,
- generate_activity_id,
- verify_activity,
- verify_community,
- },
+ activities::{following::follow::FollowCommunity, generate_activity_id, verify_activity},
context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
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_community(&self.actor, context, request_counter).await?;
self.object.verify(context, request_counter).await?;
Ok(())
}
generate_activity_id,
verify_activity,
verify_person,
+ verify_person_in_community,
},
context::lemmy_context,
fetcher::object_id::ObjectId,
verify_activity(self, &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?;
+ verify_person_in_community(&self.actor, &community, context, request_counter).await?;
Ok(())
}
use crate::{
- check_community_or_site_ban,
check_is_apub_id_valid,
fetcher::object_id::ObjectId,
generate_moderators_url,
use lemmy_api_common::blocking;
use lemmy_apub_lib::{traits::ActivityFields, verify::verify_domains_match};
use lemmy_db_schema::source::community::Community;
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views_actor::{
+ community_person_ban_view::CommunityPersonBanView,
+ community_view::CommunityView,
+};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
-use std::ops::Deref;
use strum_macros::ToString;
use url::{ParseError, Url};
use uuid::Uuid;
Ok(())
}
-pub(crate) async fn extract_community(
- cc: &[Url],
- context: &LemmyContext,
- request_counter: &mut i32,
-) -> Result<ApubCommunity, LemmyError> {
- let mut cc_iter = cc.iter();
- loop {
- if let Some(cid) = cc_iter.next() {
- let cid = ObjectId::new(cid.clone());
- if let Ok(c) = cid.dereference(context, request_counter).await {
- break Ok(c);
- }
- } else {
- return Err(anyhow!("No community found in cc").into());
- }
- }
-}
-
/// Fetches the person and community to verify their type, then checks if person is banned from site
/// or community.
pub(crate) async fn verify_person_in_community(
person_id: &ObjectId<ApubPerson>,
- community_id: &ObjectId<ApubCommunity>,
+ community: &ApubCommunity,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = community_id.dereference(context, request_counter).await?;
let person = person_id.dereference(context, request_counter).await?;
- check_community_or_site_ban(person.deref(), community.id, context.pool()).await
-}
+ if person.banned {
+ return Err(anyhow!("Person is banned from site").into());
+ }
+ let person_id = person.id;
+ let community_id = community.id;
+ let is_banned =
+ move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
+ if blocking(context.pool(), is_banned).await? {
+ return Err(anyhow!("Person is banned from community").into());
+ }
-/// Simply check that the url actually refers to a valid group.
-async fn verify_community(
- community_id: &ObjectId<ApubCommunity>,
- context: &LemmyContext,
- request_counter: &mut i32,
-) -> Result<(), LemmyError> {
- community_id.dereference(context, request_counter).await?;
Ok(())
}
use crate::{
activities::{
check_community_deleted_or_removed,
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- let community = self.cc[0].dereference(context, request_counter).await?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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)?;
match self.kind {
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for CreateOrUpdatePost {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ self
+ .object
+ .extract_community(context, request_counter)
+ .await
+ }
+}
fetcher::object_id::ObjectId,
objects::{
person::ApubPerson,
- private_message::{ApubPrivateMessage, Note},
+ private_message::{ApubPrivateMessage, ChatMessage},
},
send_lemmy_activity,
};
id: Url,
actor: ObjectId<ApubPerson>,
to: [ObjectId<ApubPerson>; 1],
- object: Note,
+ object: ChatMessage,
#[serde(rename = "type")]
kind: CreateOrUpdateType,
#[serde(flatten)]
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.to[0], context, request_counter).await?;
+ let community = self.to[0].dereference(context, request_counter).await?;
+ verify_person_in_community(&self.actor, &community, context, request_counter).await?;
Ok(())
}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ 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())?;
self.object.verify(context, request_counter).await?;
Ok(())
}
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for UndoVote {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ self.object.get_community(context, request_counter).await
+ }
+}
use crate::{
activities::{
- community::{announce::AnnouncableActivities, send_to_community},
+ community::{
+ announce::{AnnouncableActivities, GetCommunity},
+ send_to_community,
+ },
generate_activity_id,
verify_activity,
verify_is_public,
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
};
-use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
+use lemmy_db_schema::{
+ newtypes::CommunityId,
+ source::{community::Community, post::Post},
+ traits::Crud,
+};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
) -> Result<(), LemmyError> {
verify_is_public(&self.to)?;
verify_activity(self, &context.settings())?;
- verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
+ let community = self.get_community(context, request_counter).await?;
+ verify_person_in_community(&self.actor, &community, context, request_counter).await?;
Ok(())
}
}
}
}
+
+#[async_trait::async_trait(?Send)]
+impl GetCommunity for Vote {
+ async fn get_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ let object = self.object.dereference(context, request_counter).await?;
+ let cid = match object {
+ PostOrComment::Post(p) => p.community_id,
+ PostOrComment::Comment(c) => {
+ blocking(context.pool(), move |conn| Post::read(conn, c.post_id))
+ .await??
+ .community_id
+ }
+ };
+ let community = blocking(context.pool(), move |conn| Community::read(conn, cid)).await??;
+ Ok(community.into())
+ }
+}
objects::{person::ApubPerson, post::ApubPost},
};
use activitystreams::{
- base::AnyBase, chrono::NaiveDateTime, collection::kind::OrderedCollectionType,
- primitives::OneOrMany, url::Url,
+ base::AnyBase,
+ chrono::NaiveDateTime,
+ collection::kind::OrderedCollectionType,
+ primitives::OneOrMany,
+ url::Url,
};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
use crate::{
activities::{
- community::announce::{AnnouncableActivities, AnnounceActivity},
- extract_community,
+ community::announce::{AnnouncableActivities, AnnounceActivity, GetCommunity},
following::{follow::FollowCommunity, undo::UndoFollowCommunity},
report::Report,
+ verify_person_in_community,
},
collections::{
community_moderators::ApubCommunityModerators,
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
-use lemmy_apub_lib::traits::{ActivityFields, ActivityHandler, ApubObject};
+use lemmy_apub_lib::{
+ traits::{ActivityFields, ActivityHandler, ActorType, ApubObject},
+ verify::verify_domains_match,
+};
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
use lemmy_utils::LemmyError;
context: &LemmyContext,
) -> Result<HttpResponse, LemmyError> {
let res = receive_activity(request, activity.clone(), context).await;
- if let GroupInboxActivities::AnnouncableActivities(announcable) = activity.clone() {
- let community = extract_community(&announcable.cc(), context, &mut 0).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_domains_match(&community.actor_id(), announcable.id_unchecked())?;
+ verify_person_in_community(&actor_id, &community, context, &mut 0).await?;
if community.local {
AnnounceActivity::send(announcable, &community, vec![], context).await?;
}
}
+
res
}
traits::ActorType,
webfinger::{webfinger_resolve_actor, WebfingerType},
};
-use lemmy_db_schema::{
- newtypes::{CommunityId, DbUrl},
- source::{activity::Activity, person::Person},
- DbPool,
-};
-use lemmy_db_views_actor::community_person_ban_view::CommunityPersonBanView;
+use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::info;
Ok(())
}
-#[async_trait::async_trait(?Send)]
-pub trait CommunityType {
- fn followers_url(&self) -> Url;
- async fn get_follower_inboxes(
- &self,
- pool: &DbPool,
- settings: &Settings,
- ) -> Result<Vec<Url>, LemmyError>;
-}
-
pub enum EndpointType {
Community,
Person,
Ok(())
}
-async fn check_community_or_site_ban(
- person: &Person,
- community_id: CommunityId,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- if person.banned {
- return Err(anyhow!("Person is banned from site").into());
- }
- let person_id = person.id;
- let is_banned =
- move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
- if blocking(pool, is_banned).await? {
- return Err(anyhow!("Person is banned from community").into());
- }
-
- Ok(())
-}
-
pub(crate) async fn send_lemmy_activity<T: Serialize>(
context: &LemmyContext,
activity: &T,
activities::{verify_is_public, verify_person_in_community},
context::lemmy_context,
fetcher::object_id::ObjectId,
- objects::{person::ApubPerson, post::ApubPost, tombstone::Tombstone, Source},
+ objects::{
+ community::ApubCommunity,
+ person::ApubPerson,
+ post::ApubPost,
+ tombstone::Tombstone,
+ Source,
+ },
PostOrComment,
};
use activitystreams::{
) -> Result<(), LemmyError> {
let (post, _parent_comment_id) = self.get_parents(context, request_counter).await?;
let community_id = post.community_id;
- let community = blocking(context.pool(), move |conn| {
+ let community: ApubCommunity = blocking(context.pool(), move |conn| {
Community::read(conn, community_id)
})
- .await??;
+ .await??
+ .into();
if post.locked {
return Err(anyhow!("Post is locked").into());
}
verify_domains_match(self.attributed_to.inner(), &self.id)?;
- verify_person_in_community(
- &self.attributed_to,
- &ObjectId::new(community.actor_id),
- context,
- request_counter,
- )
- .await?;
+ verify_person_in_community(&self.attributed_to, &community, context, request_counter).await?;
verify_is_public(&self.to)?;
Ok(())
}
.dereference(context, request_counter)
.await?;
let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
+ let community_id = post.community_id;
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, community_id)
+ })
+ .await??;
+ verify_person_in_community(
+ ¬e.attributed_to,
+ &community.into(),
+ context,
+ request_counter,
+ )
+ .await?;
if post.locked {
return Err(anyhow!("Post is locked").into());
}
generate_moderators_url,
generate_outbox_url,
objects::{get_summary_from_string_or_source, tombstone::Tombstone, ImageObject, Source},
- CommunityType,
};
use activitystreams::{
actor::{kind::GroupType, Endpoints},
context: OneOrMany<AnyBase>,
#[serde(rename = "type")]
kind: GroupType,
- id: Url,
+ pub(crate) id: Url,
/// username, set at account creation and can never be changed
preferred_username: String,
/// title (can be changed at any time)
}
impl Group {
- pub(crate) fn id(&self, expected_domain: &Url) -> Result<&Url, LemmyError> {
- verify_domains_match(&self.id, expected_domain)?;
- Ok(&self.id)
- }
pub(crate) async fn from_apub_to_form(
group: &Group,
expected_domain: &Url,
settings: &Settings,
) -> Result<CommunityForm, LemmyError> {
- let actor_id = Some(group.id(expected_domain)?.clone().into());
+ verify_domains_match(expected_domain, &group.id)?;
let name = group.preferred_username.clone();
let title = group.name.clone();
let description = get_summary_from_string_or_source(&group.summary, &group.source);
updated: group.updated.map(|u| u.naive_local()),
deleted: None,
nsfw: Some(group.sensitive.unwrap_or(false)),
- actor_id,
+ actor_id: Some(group.id.clone().into()),
local: Some(false),
private_key: None,
public_key: Some(group.public_key.public_key_pem.clone()),
}
}
-#[async_trait::async_trait(?Send)]
-impl CommunityType for Community {
- fn followers_url(&self) -> Url {
- self.followers_url.clone().into()
- }
-
+impl ApubCommunity {
/// For a given community, returns the inboxes of all followers.
- async fn get_follower_inboxes(
+ pub(crate) async fn get_follower_inboxes(
&self,
pool: &DbPool,
settings: &Settings,
use crate::{
- activities::{extract_community, verify_is_public, verify_person_in_community},
+ activities::{verify_is_public, verify_person_in_community},
context::lemmy_context,
fetcher::object_id::ObjectId,
- objects::{person::ApubPerson, tombstone::Tombstone, ImageObject, Source},
+ objects::{
+ community::ApubCommunity,
+ person::ApubPerson,
+ tombstone::Tombstone,
+ ImageObject,
+ Source,
+ },
};
use activitystreams::{
base::AnyBase,
public,
unparsed::Unparsed,
};
+use anyhow::anyhow;
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
- traits::{ActorType, ApubObject},
+ traits::ApubObject,
values::{MediaTypeHtml, MediaTypeMarkdown},
verify::verify_domains_match,
};
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let community = extract_community(&self.to, context, request_counter).await?;
+ let community = self.extract_community(context, request_counter).await?;
check_slurs(&self.name, &context.settings().slur_regex())?;
verify_domains_match(self.attributed_to.inner(), &self.id.clone())?;
- verify_person_in_community(
- &self.attributed_to,
- &ObjectId::new(community.actor_id()),
- context,
- request_counter,
- )
- .await?;
+ verify_person_in_community(&self.attributed_to, &community, context, request_counter).await?;
verify_is_public(&self.to.clone())?;
Ok(())
}
+
+ pub(crate) async fn extract_community(
+ &self,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+ ) -> Result<ApubCommunity, LemmyError> {
+ let mut to_iter = self.to.iter();
+ loop {
+ if let Some(cid) = to_iter.next() {
+ let cid = ObjectId::new(cid.clone());
+ if let Ok(c) = cid.dereference(context, request_counter).await {
+ break Ok(c);
+ }
+ } else {
+ return Err(anyhow!("No community found in cc").into());
+ }
+ }
+ }
}
#[derive(Clone, Debug)]
.attributed_to
.dereference(context, request_counter)
.await?;
- let community = extract_community(&page.to, context, request_counter).await?;
+ let community = page.extract_community(context, request_counter).await?;
+ verify_person_in_community(&page.attributed_to, &community, context, request_counter).await?;
let thumbnail_url: Option<Url> = page.image.clone().map(|i| i.url);
let (metadata_res, pictrs_thumbnail) = if let Some(url) = &page.url {
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct Note {
+pub struct ChatMessage {
#[serde(rename = "@context")]
context: OneOrMany<AnyBase>,
r#type: ChatMessageType,
ChatMessage,
}
-impl Note {
+impl ChatMessage {
pub(crate) fn id_unchecked(&self) -> &Url {
&self.id
}
#[async_trait::async_trait(?Send)]
impl ApubObject for ApubPrivateMessage {
type DataType = LemmyContext;
- type ApubType = Note;
+ type ApubType = ChatMessage;
type TombstoneType = Tombstone;
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
unimplemented!()
}
- async fn to_apub(&self, context: &LemmyContext) -> Result<Note, LemmyError> {
+ async fn to_apub(&self, context: &LemmyContext) -> Result<ChatMessage, LemmyError> {
let creator_id = self.creator_id;
let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??;
let recipient =
blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??;
- let note = Note {
+ let note = ChatMessage {
context: lemmy_context(),
r#type: ChatMessageType::ChatMessage,
id: self.ap_id.clone().into(),
}
async fn from_apub(
- note: &Note,
+ note: &ChatMessage,
context: &LemmyContext,
expected_domain: &Url,
request_counter: &mut i32,
pub trait ActivityFields {
fn id_unchecked(&self) -> &Url;
fn actor(&self) -> &Url;
- fn cc(&self) -> Vec<Url>;
}
#[async_trait::async_trait(?Send)]
let impl_actor = variants
.iter()
.map(|v| generate_match_arm(&name, v, "e! {a.actor()}));
- let impl_cc = variants
- .iter()
- .map(|v| generate_match_arm(&name, v, "e! {a.cc()}));
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)* } }
- fn cc(&self) -> Vec<url::Url> { match self { #(#impl_cc)* } }
}
}
}
- Data::Struct(s) => {
- // check if the struct has a field "cc", and generate impl for cc() function depending on that
- let has_cc = if let syn::Fields::Named(n) = s.fields {
- n.named
- .iter()
- .any(|i| format!("{}", i.ident.as_ref().unwrap()) == "cc")
- } else {
- unimplemented!()
- };
- let cc_impl = if has_cc {
- quote! {self.cc.iter().map(|i| i.clone().into()).collect()}
- } else {
- quote! {vec![]}
- };
+ 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() }
- fn cc(&self) -> Vec<url::Url> { #cc_impl }
}
}
}