]> Untitled Git - lemmy.git/blob - server/src/apub/inbox/shared_inbox.rs
Some apub fixes
[lemmy.git] / server / src / apub / inbox / shared_inbox.rs
1 use crate::{
2   apub::{
3     check_is_apub_id_valid,
4     community::do_announce,
5     extensions::signatures::verify,
6     fetcher::{
7       get_or_fetch_and_upsert_actor,
8       get_or_fetch_and_upsert_community,
9       get_or_fetch_and_upsert_user,
10     },
11     inbox::activities::{
12       announce::receive_announce,
13       create::receive_create,
14       delete::receive_delete,
15       dislike::receive_dislike,
16       like::receive_like,
17       remove::receive_remove,
18       undo::receive_undo,
19       update::receive_update,
20     },
21     insert_activity,
22   },
23   routes::{ChatServerParam, DbPoolParam},
24   DbPool,
25   LemmyError,
26 };
27 use activitystreams::{
28   activity::{ActorAndObject, ActorAndObjectRef},
29   base::{AsBase, Extends},
30   object::AsObject,
31   prelude::*,
32 };
33 use actix_web::{client::Client, web, HttpRequest, HttpResponse};
34 use lemmy_db::user::User_;
35 use log::debug;
36 use serde::{Deserialize, Serialize};
37 use std::fmt::Debug;
38 use url::Url;
39
40 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
41 #[serde(rename_all = "PascalCase")]
42 pub enum ValidTypes {
43   Create,
44   Update,
45   Like,
46   Dislike,
47   Delete,
48   Undo,
49   Remove,
50   Announce,
51 }
52
53 // TODO: this isnt entirely correct, cause some of these activities are not ActorAndObject,
54 //       but it might still work due to the anybase conversion
55 pub type AcceptedActivities = ActorAndObject<ValidTypes>;
56
57 /// Handler for all incoming activities to user inboxes.
58 pub async fn shared_inbox(
59   request: HttpRequest,
60   input: web::Json<AcceptedActivities>,
61   client: web::Data<Client>,
62   pool: DbPoolParam,
63   chat_server: ChatServerParam,
64 ) -> Result<HttpResponse, LemmyError> {
65   let activity = input.into_inner();
66
67   let json = serde_json::to_string(&activity)?;
68   debug!("Shared inbox received activity: {}", json);
69
70   let sender = &activity.actor()?.to_owned().single_xsd_any_uri().unwrap();
71   let community = get_community_id_from_activity(&activity)?;
72
73   check_is_apub_id_valid(sender)?;
74   check_is_apub_id_valid(&community)?;
75
76   let actor = get_or_fetch_and_upsert_actor(sender, &client, &pool).await?;
77   verify(&request, actor.as_ref())?;
78
79   let any_base = activity.clone().into_any_base()?;
80   let kind = activity.kind().unwrap();
81   let res = match kind {
82     ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
83     ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
84     ValidTypes::Update => receive_update(any_base, &client, &pool, chat_server).await,
85     ValidTypes::Like => receive_like(any_base, &client, &pool, chat_server).await,
86     ValidTypes::Dislike => receive_dislike(any_base, &client, &pool, chat_server).await,
87     ValidTypes::Remove => receive_remove(any_base, &client, &pool, chat_server).await,
88     ValidTypes::Delete => receive_delete(any_base, &client, &pool, chat_server).await,
89     ValidTypes::Undo => receive_undo(any_base, &client, &pool, chat_server).await,
90   };
91
92   insert_activity(actor.user_id(), activity.clone(), false, &pool).await?;
93   res
94 }
95
96 pub(in crate::apub::inbox) fn receive_unhandled_activity<A>(
97   activity: A,
98 ) -> Result<HttpResponse, LemmyError>
99 where
100   A: Debug,
101 {
102   debug!("received unhandled activity type: {:?}", activity);
103   Ok(HttpResponse::NotImplemented().finish())
104 }
105
106 pub(in crate::apub::inbox) async fn get_user_from_activity<T, A>(
107   activity: &T,
108   client: &Client,
109   pool: &DbPool,
110 ) -> Result<User_, LemmyError>
111 where
112   T: AsBase<A> + ActorAndObjectRef,
113 {
114   let actor = activity.actor()?;
115   let user_uri = actor.as_single_xsd_any_uri().unwrap();
116   get_or_fetch_and_upsert_user(&user_uri, client, pool).await
117 }
118
119 pub(in crate::apub::inbox) fn get_community_id_from_activity<T, A>(
120   activity: &T,
121 ) -> Result<Url, LemmyError>
122 where
123   T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
124 {
125   let cc = activity.cc().unwrap();
126   let cc = cc.as_many().unwrap();
127   Ok(cc.first().unwrap().as_xsd_any_uri().unwrap().to_owned())
128 }
129
130 pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
131   activity: T,
132   user: &User_,
133   client: &Client,
134   pool: &DbPool,
135 ) -> Result<(), LemmyError>
136 where
137   T: AsObject<Kind>,
138   T: Extends<Kind>,
139   Kind: Serialize,
140   <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
141 {
142   let cc = activity.cc().unwrap();
143   let cc = cc.as_many().unwrap();
144   let community_followers_uri = cc.first().unwrap().as_xsd_any_uri().unwrap();
145   // TODO: this is hacky but seems to be the only way to get the community ID
146   let community_uri = community_followers_uri
147     .to_string()
148     .replace("/followers", "");
149   let community =
150     get_or_fetch_and_upsert_community(&Url::parse(&community_uri)?, client, pool).await?;
151
152   if community.local {
153     do_announce(activity.into_any_base()?, &community, &user, client, pool).await?;
154   }
155   Ok(())
156 }