]> Untitled Git - lemmy.git/blob - crates/apub/src/http/mod.rs
52a0144348f0c8197e98a4c94da6625e2ae5aa91
[lemmy.git] / crates / apub / src / http / mod.rs
1 use crate::{
2   activity_lists::SharedInboxActivities,
3   fetcher::user_or_community::UserOrCommunity,
4   protocol::objects::tombstone::Tombstone,
5   CONTEXT,
6 };
7 use activitypub_federation::{
8   actix_web::inbox::receive_activity,
9   config::Data,
10   protocol::context::WithContext,
11   FEDERATION_CONTENT_TYPE,
12 };
13 use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
14 use http::StatusCode;
15 use lemmy_api_common::context::LemmyContext;
16 use lemmy_db_schema::source::activity::Activity;
17 use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
18 use serde::{Deserialize, Serialize};
19 use std::ops::Deref;
20 use url::Url;
21
22 mod comment;
23 mod community;
24 mod person;
25 mod post;
26 pub mod routes;
27 pub mod site;
28
29 pub async fn shared_inbox(
30   request: HttpRequest,
31   body: Bytes,
32   data: Data<LemmyContext>,
33 ) -> LemmyResult<HttpResponse> {
34   receive_activity::<SharedInboxActivities, UserOrCommunity, LemmyContext>(request, body, &data)
35     .await
36 }
37
38 /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub
39 /// headers.
40 ///
41 /// actix-web doesn't allow pretty-print for json so we need to do this manually.
42 fn create_apub_response<T>(data: &T) -> LemmyResult<HttpResponse>
43 where
44   T: Serialize,
45 {
46   let json = serde_json::to_string_pretty(&WithContext::new(data, CONTEXT.clone()))?;
47
48   Ok(
49     HttpResponse::Ok()
50       .content_type(FEDERATION_CONTENT_TYPE)
51       .body(json),
52   )
53 }
54
55 fn create_apub_tombstone_response<T: Into<Url>>(id: T) -> LemmyResult<HttpResponse> {
56   let tombstone = Tombstone::new(id.into());
57   let json = serde_json::to_string_pretty(&WithContext::new(tombstone, CONTEXT.deref().clone()))?;
58
59   Ok(
60     HttpResponse::Gone()
61       .content_type(FEDERATION_CONTENT_TYPE)
62       .status(StatusCode::GONE)
63       .body(json),
64   )
65 }
66
67 fn err_object_not_local() -> LemmyError {
68   LemmyErrorType::ObjectNotLocal.into()
69 }
70
71 #[derive(Deserialize)]
72 pub struct ActivityQuery {
73   type_: String,
74   id: String,
75 }
76
77 /// Return the ActivityPub json representation of a local activity over HTTP.
78 #[tracing::instrument(skip_all)]
79 pub(crate) async fn get_activity(
80   info: web::Path<ActivityQuery>,
81   context: web::Data<LemmyContext>,
82 ) -> Result<HttpResponse, LemmyError> {
83   let settings = context.settings();
84   let activity_id = Url::parse(&format!(
85     "{}/activities/{}/{}",
86     settings.get_protocol_and_hostname(),
87     info.type_,
88     info.id
89   ))?
90   .into();
91   let activity = Activity::read_from_apub_id(&mut context.pool(), &activity_id).await?;
92
93   let sensitive = activity.sensitive;
94   if !activity.local {
95     Err(err_object_not_local())
96   } else if sensitive {
97     Ok(HttpResponse::Forbidden().finish())
98   } else {
99     create_apub_response(&activity.data)
100   }
101 }