4 receive_delete_community,
5 receive_remove_community,
6 receive_undo_delete_community,
7 receive_undo_remove_community,
10 receive_create_private_message,
11 receive_delete_private_message,
12 receive_undo_delete_private_message,
13 receive_update_private_message,
15 receive_unhandled_activity,
16 verify_activity_domains_valid,
18 check_is_apub_id_valid,
19 fetcher::get_or_fetch_and_upsert_community,
22 get_activity_to_and_cc,
23 inbox_verify_http_signature,
24 is_activity_already_known,
25 is_addressed_to_public,
26 receive_for_community::{
27 receive_create_for_community,
28 receive_delete_for_community,
29 receive_dislike_for_community,
30 receive_like_for_community,
31 receive_remove_for_community,
32 receive_undo_for_community,
33 receive_update_for_community,
39 use activitystreams::{
40 activity::{Accept, ActorAndObject, Announce, Delete, Follow, Undo},
44 use actix_web::{web, HttpRequest, HttpResponse};
45 use anyhow::{anyhow, Context};
48 community::{Community, CommunityFollower, CommunityFollowerForm},
49 private_message::PrivateMessage,
53 use lemmy_structs::blocking;
54 use lemmy_utils::{location_info, LemmyError};
55 use lemmy_websocket::LemmyContext;
57 use serde::{Deserialize, Serialize};
61 /// Allowed activities for user inbox.
62 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
63 #[serde(rename_all = "PascalCase")]
64 pub enum UserValidTypes {
65 Accept, // community accepted our follow request
66 Create, // create private message
67 Update, // edit private message
68 Delete, // private message or community deleted by creator
69 Undo, // private message or community restored
70 Remove, // community removed by admin
71 Announce, // post, comment or vote in community
74 pub type UserAcceptedActivities = ActorAndObject<UserValidTypes>;
76 /// Handler for all incoming activities to user inboxes.
77 pub async fn user_inbox(
79 input: web::Json<UserAcceptedActivities>,
80 path: web::Path<String>,
81 context: web::Data<LemmyContext>,
82 ) -> Result<HttpResponse, LemmyError> {
83 let activity = input.into_inner();
84 // First of all check the http signature
85 let request_counter = &mut 0;
86 let actor = inbox_verify_http_signature(&activity, &context, request, request_counter).await?;
88 // Do nothing if we received the same activity before
89 let activity_id = get_activity_id(&activity, &actor.actor_id()?)?;
90 if is_activity_already_known(context.pool(), &activity_id).await? {
91 return Ok(HttpResponse::Ok().finish());
94 // Check if the activity is actually meant for us
95 let username = path.into_inner();
96 let user = blocking(&context.pool(), move |conn| {
97 User_::read_from_name(&conn, &username)
100 let to_and_cc = get_activity_to_and_cc(&activity)?;
101 if !to_and_cc.contains(&&user.actor_id()?) {
102 return Err(anyhow!("Activity delivered to wrong user").into());
105 insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
108 "User {} received activity {:?} from {}",
110 &activity.id_unchecked(),
111 &actor.actor_id_str()
114 user_receive_message(
124 /// Receives Accept/Follow, Announce, private messages and community (undo) remove, (undo) delete
125 pub(crate) async fn user_receive_message(
126 activity: UserAcceptedActivities,
127 to_user: Option<User_>,
128 actor: &dyn ActorType,
129 context: &LemmyContext,
130 request_counter: &mut i32,
131 ) -> Result<HttpResponse, LemmyError> {
132 // TODO: must be addressed to one or more local users, or to followers of a remote community
134 // TODO: if it is addressed to community followers, check that at least one local user is following it
136 let any_base = activity.clone().into_any_base()?;
137 let kind = activity.kind().context(location_info!())?;
138 let actor_url = actor.actor_id()?;
140 UserValidTypes::Accept => {
141 receive_accept(&context, any_base, actor, to_user.unwrap(), request_counter).await?;
143 UserValidTypes::Announce => {
144 receive_announce(&context, any_base, actor, request_counter).await?
146 UserValidTypes::Create => {
147 receive_create_private_message(&context, any_base, actor_url, request_counter).await?
149 UserValidTypes::Update => {
150 receive_update_private_message(&context, any_base, actor_url, request_counter).await?
152 UserValidTypes::Delete => {
153 receive_delete(context, any_base, &actor_url, request_counter).await?
155 UserValidTypes::Undo => receive_undo(context, any_base, &actor_url, request_counter).await?,
156 UserValidTypes::Remove => receive_remove_community(&context, any_base, &actor_url).await?,
159 // TODO: would be logical to move websocket notification code here
161 Ok(HttpResponse::Ok().finish())
164 /// Handle accepted follows.
165 async fn receive_accept(
166 context: &LemmyContext,
168 actor: &dyn ActorType,
170 request_counter: &mut i32,
171 ) -> Result<(), LemmyError> {
172 let accept = Accept::from_any_base(activity)?.context(location_info!())?;
173 verify_activity_domains_valid(&accept, &actor.actor_id()?, false)?;
175 // TODO: we should check that we actually sent this activity, because the remote instance
176 // could just put a fake Follow
177 let object = accept.object().to_owned().one().context(location_info!())?;
178 let follow = Follow::from_any_base(object)?.context(location_info!())?;
179 verify_activity_domains_valid(&follow, &user.actor_id()?, false)?;
181 let community_uri = accept
184 .single_xsd_any_uri()
185 .context(location_info!())?;
188 get_or_fetch_and_upsert_community(&community_uri, context, request_counter).await?;
190 // Now you need to add this to the community follower
191 let community_follower_form = CommunityFollowerForm {
192 community_id: community.id,
196 // This will fail if they're already a follower
197 blocking(&context.pool(), move |conn| {
198 CommunityFollower::follow(conn, &community_follower_form).ok()
205 /// Takes an announce and passes the inner activity to the appropriate handler.
206 async fn receive_announce(
207 context: &LemmyContext,
209 actor: &dyn ActorType,
210 request_counter: &mut i32,
211 ) -> Result<(), LemmyError> {
212 let announce = Announce::from_any_base(activity)?.context(location_info!())?;
213 verify_activity_domains_valid(&announce, &actor.actor_id()?, false)?;
214 is_addressed_to_public(&announce)?;
216 let kind = announce.object().as_single_kind_str();
217 let inner_activity = announce
221 .context(location_info!())?;
223 let inner_id = inner_activity.id().context(location_info!())?.to_owned();
224 check_is_apub_id_valid(&inner_id)?;
225 if is_activity_already_known(context.pool(), &inner_id).await? {
232 receive_create_for_community(context, inner_activity, &inner_id, request_counter).await
235 receive_update_for_community(context, inner_activity, &inner_id, request_counter).await
238 receive_like_for_community(context, inner_activity, &inner_id, request_counter).await
241 receive_dislike_for_community(context, inner_activity, &inner_id, request_counter).await
243 Some("Delete") => receive_delete_for_community(context, inner_activity, &inner_id).await,
244 Some("Remove") => receive_remove_for_community(context, inner_activity, &inner_id).await,
246 receive_undo_for_community(context, inner_activity, &inner_id, request_counter).await
248 _ => receive_unhandled_activity(inner_activity),
252 async fn receive_delete(
253 context: &LemmyContext,
255 expected_domain: &Url,
256 request_counter: &mut i32,
257 ) -> Result<(), LemmyError> {
258 use CommunityOrPrivateMessage::*;
260 let delete = Delete::from_any_base(any_base.clone())?.context(location_info!())?;
261 verify_activity_domains_valid(&delete, expected_domain, true)?;
262 let object_uri = delete
265 .single_xsd_any_uri()
266 .context(location_info!())?;
268 match find_community_or_private_message_by_id(context, object_uri).await? {
269 Community(c) => receive_delete_community(context, c).await,
270 PrivateMessage(p) => receive_delete_private_message(context, delete, p, request_counter).await,
274 async fn receive_undo(
275 context: &LemmyContext,
277 expected_domain: &Url,
278 request_counter: &mut i32,
279 ) -> Result<(), LemmyError> {
280 use CommunityOrPrivateMessage::*;
281 let undo = Undo::from_any_base(any_base)?.context(location_info!())?;
282 verify_activity_domains_valid(&undo, expected_domain, true)?;
284 let inner_activity = undo.object().to_owned().one().context(location_info!())?;
285 let kind = inner_activity.kind_str();
288 let delete = Delete::from_any_base(inner_activity)?.context(location_info!())?;
289 verify_activity_domains_valid(&delete, expected_domain, true)?;
290 let object_uri = delete
293 .single_xsd_any_uri()
294 .context(location_info!())?;
295 match find_community_or_private_message_by_id(context, object_uri).await? {
296 Community(c) => receive_undo_delete_community(context, undo, c, expected_domain).await,
297 PrivateMessage(p) => {
298 receive_undo_delete_private_message(context, undo, expected_domain, p, request_counter)
303 Some("Remove") => receive_undo_remove_community(context, undo, expected_domain).await,
304 _ => receive_unhandled_activity(undo),
307 enum CommunityOrPrivateMessage {
308 Community(Community),
309 PrivateMessage(PrivateMessage),
312 async fn find_community_or_private_message_by_id(
313 context: &LemmyContext,
315 ) -> Result<CommunityOrPrivateMessage, LemmyError> {
316 let ap_id = apub_id.to_string();
317 let community = blocking(context.pool(), move |conn| {
318 Community::read_from_actor_id(conn, &ap_id)
321 if let Ok(c) = community {
322 return Ok(CommunityOrPrivateMessage::Community(c));
325 let ap_id = apub_id.to_string();
326 let private_message = blocking(context.pool(), move |conn| {
327 PrivateMessage::read_from_apub_id(conn, &ap_id)
330 if let Ok(p) = private_message {
331 return Ok(CommunityOrPrivateMessage::PrivateMessage(p));
334 return Err(NotFound.into());