]> Untitled Git - lemmy.git/blob - crates/apub_receive/src/inbox/mod.rs
Running clippy --fix (#1647)
[lemmy.git] / crates / apub_receive / src / inbox / mod.rs
1 use activitystreams::{
2   activity::ActorAndObjectRefExt,
3   base::{AsBase, BaseExt, Extends},
4   object::AsObject,
5   public,
6 };
7 use actix_web::HttpRequest;
8 use anyhow::{anyhow, Context};
9 use lemmy_api_common::blocking;
10 use lemmy_apub::{
11   check_is_apub_id_valid,
12   extensions::signatures::verify_signature,
13   fetcher::get_or_fetch_and_upsert_actor,
14   get_activity_to_and_cc,
15   ActorType,
16 };
17 use lemmy_db_queries::{
18   source::{activity::Activity_, community::Community_},
19   ApubObject,
20   DbPool,
21 };
22 use lemmy_db_schema::source::{activity::Activity, community::Community, person::Person};
23 use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
24 use lemmy_websocket::LemmyContext;
25 use serde::Serialize;
26 use std::fmt::Debug;
27 use url::Url;
28
29 pub mod community_inbox;
30 pub mod person_inbox;
31 pub(crate) mod receive_for_community;
32 pub mod shared_inbox;
33
34 pub(crate) fn get_activity_id<T, Kind>(activity: &T, creator_uri: &Url) -> Result<Url, LemmyError>
35 where
36   T: BaseExt<Kind> + Extends<Kind> + Debug,
37   Kind: Serialize,
38   <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
39 {
40   let creator_domain = creator_uri.host_str().context(location_info!())?;
41   let activity_id = activity.id(creator_domain)?;
42   Ok(activity_id.context(location_info!())?.to_owned())
43 }
44
45 pub(crate) async fn is_activity_already_known(
46   pool: &DbPool,
47   activity_id: &Url,
48 ) -> Result<bool, LemmyError> {
49   let activity_id = activity_id.to_owned().into();
50   let existing = blocking(pool, move |conn| {
51     Activity::read_from_apub_id(conn, &activity_id)
52   })
53   .await?;
54   match existing {
55     Ok(_) => Ok(true),
56     Err(_) => Ok(false),
57   }
58 }
59
60 pub(crate) fn verify_is_addressed_to_public<T, Kind>(activity: &T) -> Result<(), LemmyError>
61 where
62   T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
63 {
64   let to_and_cc = get_activity_to_and_cc(activity);
65   if to_and_cc.contains(&public()) {
66     Ok(())
67   } else {
68     Err(anyhow!("Activity is not addressed to public").into())
69   }
70 }
71
72 pub(crate) async fn inbox_verify_http_signature<T, Kind>(
73   activity: &T,
74   context: &LemmyContext,
75   request: HttpRequest,
76   request_counter: &mut i32,
77 ) -> Result<Box<dyn ActorType>, LemmyError>
78 where
79   T: AsObject<Kind> + ActorAndObjectRefExt + Extends<Kind> + AsBase<Kind>,
80   Kind: Serialize,
81   <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
82 {
83   let actor_id = activity
84     .actor()?
85     .to_owned()
86     .single_xsd_any_uri()
87     .context(location_info!())?;
88   check_is_apub_id_valid(&actor_id, false)?;
89   let actor = get_or_fetch_and_upsert_actor(&actor_id, context, request_counter).await?;
90   verify_signature(&request, actor.as_ref())?;
91   Ok(actor)
92 }
93
94 /// Returns true if `to_and_cc` contains at least one local user.
95 pub(crate) async fn is_addressed_to_local_person(
96   to_and_cc: &[Url],
97   pool: &DbPool,
98 ) -> Result<bool, LemmyError> {
99   for url in to_and_cc {
100     let url = url.to_owned();
101     let person = blocking(pool, move |conn| {
102       Person::read_from_apub_id(conn, &url.into())
103     })
104     .await?;
105     if let Ok(u) = person {
106       if u.local {
107         return Ok(true);
108       }
109     }
110   }
111   Ok(false)
112 }
113
114 /// If `to_and_cc` contains the followers collection of a remote community, returns this community
115 /// (like `https://example.com/c/main/followers`)
116 pub(crate) async fn is_addressed_to_community_followers(
117   to_and_cc: &[Url],
118   pool: &DbPool,
119 ) -> Result<Option<Community>, LemmyError> {
120   for url in to_and_cc {
121     let url = url.to_owned().into();
122     let community = blocking(pool, move |conn| {
123       // ignore errors here, because the current url might not actually be a followers url
124       Community::read_from_followers_url(conn, &url).ok()
125     })
126     .await?;
127     if let Some(c) = community {
128       if !c.local {
129         return Ok(Some(c));
130       }
131     }
132   }
133   Ok(None)
134 }
135
136 pub(in crate::inbox) fn assert_activity_not_local<T, Kind>(activity: &T) -> Result<(), LemmyError>
137 where
138   T: BaseExt<Kind> + Debug,
139 {
140   let id = activity.id_unchecked().context(location_info!())?;
141   let activity_domain = id.domain().context(location_info!())?;
142
143   if activity_domain == Settings::get().hostname() {
144     return Err(
145       anyhow!(
146         "Error: received activity which was sent by local instance: {:?}",
147         activity
148       )
149       .into(),
150     );
151   }
152   Ok(())
153 }