2 activities::receive::verify_activity_domains_valid,
3 check_is_apub_id_valid,
4 extensions::signatures::verify_signature,
5 fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_community},
6 inbox::{get_activity_id, is_activity_already_known},
11 use activitystreams::{
12 activity::{Accept, ActorAndObject, Create, Delete, Follow, Undo, Update},
17 use actix_web::{web, HttpRequest, HttpResponse};
18 use anyhow::{anyhow, Context};
20 community::{CommunityFollower, CommunityFollowerForm},
21 private_message::{PrivateMessage, PrivateMessageForm},
22 private_message_view::PrivateMessageView,
27 use lemmy_structs::{blocking, user::PrivateMessageResponse};
28 use lemmy_utils::{location_info, LemmyError};
29 use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
31 use serde::{Deserialize, Serialize};
34 /// Allowed activities for user inbox.
35 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
36 #[serde(rename_all = "PascalCase")]
45 pub type AcceptedActivities = ActorAndObject<ValidTypes>;
47 /// Handler for all incoming activities to user inboxes.
48 pub async fn user_inbox(
50 input: web::Json<AcceptedActivities>,
51 path: web::Path<String>,
52 context: web::Data<LemmyContext>,
53 ) -> Result<HttpResponse, LemmyError> {
54 let activity = input.into_inner();
55 let username = path.into_inner();
56 let user = blocking(&context.pool(), move |conn| {
57 User_::read_from_name(&conn, &username)
63 .context(location_info!())?
65 .single_xsd_any_uri();
66 if Some(user.actor_id()?) != to {
67 return Err(anyhow!("Activity delivered to wrong user").into());
70 let actor_uri = activity
72 .as_single_xsd_any_uri()
73 .context(location_info!())?;
75 "User {} inbox received activity {:?} from {}",
77 &activity.id_unchecked(),
81 check_is_apub_id_valid(actor_uri)?;
83 let request_counter = &mut 0;
84 let actor = get_or_fetch_and_upsert_actor(actor_uri, &context, request_counter).await?;
85 verify_signature(&request, actor.as_ref())?;
87 let activity_id = get_activity_id(&activity, actor_uri)?;
88 if is_activity_already_known(context.pool(), &activity_id).await? {
89 return Ok(HttpResponse::Ok().finish());
92 let any_base = activity.clone().into_any_base()?;
93 let kind = activity.kind().context(location_info!())?;
94 let res = match kind {
95 ValidTypes::Accept => {
96 receive_accept(&context, any_base, actor.as_ref(), user, request_counter).await
98 ValidTypes::Create => {
99 receive_create_private_message(&context, any_base, actor.as_ref(), request_counter).await
101 ValidTypes::Update => {
102 receive_update_private_message(&context, any_base, actor.as_ref(), request_counter).await
104 ValidTypes::Delete => receive_delete_private_message(&context, any_base, actor.as_ref()).await,
105 ValidTypes::Undo => {
106 receive_undo_delete_private_message(&context, any_base, actor.as_ref()).await
110 insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
114 /// Handle accepted follows.
115 async fn receive_accept(
116 context: &LemmyContext,
118 actor: &dyn ActorType,
120 request_counter: &mut i32,
121 ) -> Result<HttpResponse, LemmyError> {
122 let accept = Accept::from_any_base(activity)?.context(location_info!())?;
123 verify_activity_domains_valid(&accept, actor.actor_id()?, false)?;
125 // TODO: we should check that we actually sent this activity, because the remote instance
126 // could just put a fake Follow
127 let object = accept.object().to_owned().one().context(location_info!())?;
128 let follow = Follow::from_any_base(object)?.context(location_info!())?;
129 verify_activity_domains_valid(&follow, user.actor_id()?, false)?;
131 let community_uri = accept
134 .single_xsd_any_uri()
135 .context(location_info!())?;
138 get_or_fetch_and_upsert_community(&community_uri, context, request_counter).await?;
140 // Now you need to add this to the community follower
141 let community_follower_form = CommunityFollowerForm {
142 community_id: community.id,
146 // This will fail if they're already a follower
147 blocking(&context.pool(), move |conn| {
148 CommunityFollower::follow(conn, &community_follower_form).ok()
152 Ok(HttpResponse::Ok().finish())
155 async fn receive_create_private_message(
156 context: &LemmyContext,
158 actor: &dyn ActorType,
159 request_counter: &mut i32,
160 ) -> Result<HttpResponse, LemmyError> {
161 let create = Create::from_any_base(activity)?.context(location_info!())?;
162 verify_activity_domains_valid(&create, actor.actor_id()?, true)?;
164 let note = Note::from_any_base(
168 .context(location_info!())?
171 .context(location_info!())?;
173 let private_message =
174 PrivateMessageForm::from_apub(¬e, context, Some(actor.actor_id()?), request_counter).await?;
176 let inserted_private_message = blocking(&context.pool(), move |conn| {
177 PrivateMessage::create(conn, &private_message)
181 let message = blocking(&context.pool(), move |conn| {
182 PrivateMessageView::read(conn, inserted_private_message.id)
186 let res = PrivateMessageResponse { message };
188 let recipient_id = res.message.recipient_id;
190 context.chat_server().do_send(SendUserRoomMessage {
191 op: UserOperation::CreatePrivateMessage,
197 Ok(HttpResponse::Ok().finish())
200 async fn receive_update_private_message(
201 context: &LemmyContext,
203 actor: &dyn ActorType,
204 request_counter: &mut i32,
205 ) -> Result<HttpResponse, LemmyError> {
206 let update = Update::from_any_base(activity)?.context(location_info!())?;
207 verify_activity_domains_valid(&update, actor.actor_id()?, true)?;
212 .context(location_info!())?
214 let note = Note::from_any_base(object)?.context(location_info!())?;
216 let private_message_form =
217 PrivateMessageForm::from_apub(¬e, context, Some(actor.actor_id()?), request_counter).await?;
219 let private_message_ap_id = private_message_form
222 .context(location_info!())?
224 let private_message = blocking(&context.pool(), move |conn| {
225 PrivateMessage::read_from_apub_id(conn, &private_message_ap_id)
229 let private_message_id = private_message.id;
230 blocking(&context.pool(), move |conn| {
231 PrivateMessage::update(conn, private_message_id, &private_message_form)
235 let private_message_id = private_message.id;
236 let message = blocking(&context.pool(), move |conn| {
237 PrivateMessageView::read(conn, private_message_id)
241 let res = PrivateMessageResponse { message };
243 let recipient_id = res.message.recipient_id;
245 context.chat_server().do_send(SendUserRoomMessage {
246 op: UserOperation::EditPrivateMessage,
252 Ok(HttpResponse::Ok().finish())
255 async fn receive_delete_private_message(
256 context: &LemmyContext,
258 actor: &dyn ActorType,
259 ) -> Result<HttpResponse, LemmyError> {
260 let delete = Delete::from_any_base(activity)?.context(location_info!())?;
261 verify_activity_domains_valid(&delete, actor.actor_id()?, true)?;
263 let private_message_id = delete
266 .single_xsd_any_uri()
267 .context(location_info!())?;
268 let private_message = blocking(context.pool(), move |conn| {
269 PrivateMessage::read_from_apub_id(conn, private_message_id.as_str())
272 let deleted_private_message = blocking(context.pool(), move |conn| {
273 PrivateMessage::update_deleted(conn, private_message.id, true)
277 let message = blocking(&context.pool(), move |conn| {
278 PrivateMessageView::read(&conn, deleted_private_message.id)
282 let res = PrivateMessageResponse { message };
283 let recipient_id = res.message.recipient_id;
284 context.chat_server().do_send(SendUserRoomMessage {
285 op: UserOperation::EditPrivateMessage,
291 Ok(HttpResponse::Ok().finish())
294 async fn receive_undo_delete_private_message(
295 context: &LemmyContext,
297 actor: &dyn ActorType,
298 ) -> Result<HttpResponse, LemmyError> {
299 let undo = Undo::from_any_base(activity)?.context(location_info!())?;
300 verify_activity_domains_valid(&undo, actor.actor_id()?, true)?;
301 let object = undo.object().to_owned().one().context(location_info!())?;
302 let delete = Delete::from_any_base(object)?.context(location_info!())?;
303 verify_activity_domains_valid(&delete, actor.actor_id()?, true)?;
305 let private_message_id = delete
308 .single_xsd_any_uri()
309 .context(location_info!())?;
310 let private_message = blocking(context.pool(), move |conn| {
311 PrivateMessage::read_from_apub_id(conn, private_message_id.as_str())
314 let deleted_private_message = blocking(context.pool(), move |conn| {
315 PrivateMessage::update_deleted(conn, private_message.id, false)
319 let message = blocking(&context.pool(), move |conn| {
320 PrivateMessageView::read(&conn, deleted_private_message.id)
324 let res = PrivateMessageResponse { message };
325 let recipient_id = res.message.recipient_id;
326 context.chat_server().do_send(SendUserRoomMessage {
327 op: UserOperation::EditPrivateMessage,
333 Ok(HttpResponse::Ok().finish())