2 check_is_apub_id_valid,
3 extensions::signatures::verify_signature,
4 fetcher::get_or_fetch_and_upsert_actor,
8 activity::ActorAndObjectRefExt,
9 base::{AsBase, BaseExt, Extends},
10 object::{AsObject, ObjectExt},
13 use actix_web::HttpRequest;
14 use anyhow::{anyhow, Context};
15 use lemmy_db_queries::{source::activity::Activity_, ApubObject, DbPool};
16 use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_};
17 use lemmy_structs::blocking;
18 use lemmy_utils::{location_info, settings::Settings, LemmyError};
19 use lemmy_websocket::LemmyContext;
20 use serde::{export::fmt::Debug, Serialize};
23 pub mod community_inbox;
24 mod receive_for_community;
28 pub(crate) fn get_activity_id<T, Kind>(activity: &T, creator_uri: &Url) -> Result<Url, LemmyError>
30 T: BaseExt<Kind> + Extends<Kind> + Debug,
32 <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
34 let creator_domain = creator_uri.host_str().context(location_info!())?;
35 let activity_id = activity.id(creator_domain)?;
36 Ok(activity_id.context(location_info!())?.to_owned())
39 pub(crate) async fn is_activity_already_known(
42 ) -> Result<bool, LemmyError> {
43 let activity_id = activity_id.to_string();
44 let existing = blocking(pool, move |conn| {
45 Activity::read_from_apub_id(&conn, &activity_id)
54 pub(crate) fn get_activity_to_and_cc<T, Kind>(activity: &T) -> Vec<Url>
56 T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
58 let mut to_and_cc = vec![];
59 if let Some(to) = activity.to() {
60 let to = to.to_owned().unwrap_to_vec();
63 .map(|t| t.as_xsd_any_uri())
65 .map(|t| t.to_owned())
67 to_and_cc.append(&mut to);
69 if let Some(cc) = activity.cc() {
70 let cc = cc.to_owned().unwrap_to_vec();
73 .map(|c| c.as_xsd_any_uri())
75 .map(|c| c.to_owned())
77 to_and_cc.append(&mut cc);
82 pub(crate) fn is_addressed_to_public<T, Kind>(activity: &T) -> Result<(), LemmyError>
84 T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
86 let to_and_cc = get_activity_to_and_cc(activity);
87 if to_and_cc.contains(&public()) {
90 Err(anyhow!("Activity is not addressed to public").into())
94 pub(crate) async fn inbox_verify_http_signature<T, Kind>(
96 context: &LemmyContext,
98 request_counter: &mut i32,
99 ) -> Result<Box<dyn ActorType>, LemmyError>
101 T: AsObject<Kind> + ActorAndObjectRefExt + Extends<Kind> + AsBase<Kind>,
103 <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
105 let actor_id = activity
108 .single_xsd_any_uri()
109 .context(location_info!())?;
110 check_is_apub_id_valid(&actor_id)?;
111 let actor = get_or_fetch_and_upsert_actor(&actor_id, &context, request_counter).await?;
112 verify_signature(&request, actor.as_ref())?;
116 /// Returns true if `to_and_cc` contains at least one local user.
117 pub(crate) async fn is_addressed_to_local_user(
120 ) -> Result<bool, LemmyError> {
121 for url in to_and_cc {
122 let url = url.to_string();
123 let user = blocking(&pool, move |conn| User_::read_from_apub_id(&conn, &url)).await?;
124 if let Ok(u) = user {
133 /// If `to_and_cc` contains the followers collection of a remote community, returns this community
134 /// (like `https://example.com/c/main/followers`)
135 pub(crate) async fn is_addressed_to_community_followers(
138 ) -> Result<Option<Community>, LemmyError> {
139 for url in to_and_cc {
140 let url = url.to_string();
141 // TODO: extremely hacky, we should just store the followers url for each community in the db
142 if url.ends_with("/followers") {
143 let community_url = url.replace("/followers", "");
144 let community = blocking(&pool, move |conn| {
145 Community::read_from_apub_id(&conn, &community_url)
148 if !community.local {
149 return Ok(Some(community));
156 pub(in crate::inbox) fn assert_activity_not_local<T, Kind>(activity: &T) -> Result<(), LemmyError>
158 T: BaseExt<Kind> + Debug,
160 let id = activity.id_unchecked().context(location_info!())?;
161 let activity_domain = id.domain().context(location_info!())?;
163 if activity_domain == Settings::get().hostname {
166 "Error: received activity which was sent by local instance: {:?}",