]> Untitled Git - lemmy.git/commitdiff
Create rustdoc for activitypub code
authorFelix Ableitner <me@nutomic.com>
Mon, 19 Oct 2020 14:29:35 +0000 (16:29 +0200)
committerFelix Ableitner <me@nutomic.com>
Mon, 19 Oct 2020 14:29:35 +0000 (16:29 +0200)
25 files changed:
lemmy_apub/src/activities/receive/announce.rs
lemmy_apub/src/activities/receive/mod.rs
lemmy_apub/src/activities/send/comment.rs
lemmy_apub/src/activities/send/community.rs
lemmy_apub/src/activities/send/mod.rs
lemmy_apub/src/activities/send/post.rs
lemmy_apub/src/activities/send/private_message.rs
lemmy_apub/src/activity_queue.rs
lemmy_apub/src/extensions/group_extensions.rs
lemmy_apub/src/extensions/page_extension.rs
lemmy_apub/src/extensions/signatures.rs
lemmy_apub/src/fetcher.rs
lemmy_apub/src/http/comment.rs
lemmy_apub/src/http/community.rs
lemmy_apub/src/http/post.rs
lemmy_apub/src/http/user.rs
lemmy_apub/src/inbox/community_inbox.rs
lemmy_apub/src/inbox/shared_inbox.rs
lemmy_apub/src/inbox/user_inbox.rs
lemmy_apub/src/lib.rs
lemmy_apub/src/objects/comment.rs
lemmy_apub/src/objects/community.rs
lemmy_apub/src/objects/post.rs
lemmy_apub/src/objects/private_message.rs
lemmy_apub/src/objects/user.rs

index 3167d6b907ee5bf3f66f80f3dd729f4941352a42..5f25b58c6aa219f552909159994260c91b387cad 100644 (file)
@@ -19,6 +19,7 @@ use anyhow::Context;
 use lemmy_utils::{location_info, LemmyError};
 use lemmy_websocket::LemmyContext;
 
+/// Takes an announce and passes the inner activity to the appropriate handler.
 pub async fn receive_announce(
   context: &LemmyContext,
   activity: AnyBase,
index ab830ca79ca2289b29b4e0c182e7649b1cc9bb2a..b8ec327ae0e88ff93dd2f66ac9e17dae34c36989 100644 (file)
@@ -31,6 +31,7 @@ mod undo_comment;
 mod undo_post;
 pub mod update;
 
+/// Return HTTP 501 for unsupported activities in inbox.
 fn receive_unhandled_activity<A>(activity: A) -> Result<HttpResponse, LemmyError>
 where
   A: Debug,
@@ -39,6 +40,8 @@ where
   Ok(HttpResponse::NotImplemented().finish())
 }
 
+/// Reads the destination community from the activity's `cc` field. If this refers to a local
+/// community, the activity is announced to all community followers.
 async fn announce_if_community_is_local<T, Kind>(
   activity: T,
   user: &User_,
@@ -52,16 +55,12 @@ where
 {
   let cc = activity.cc().context(location_info!())?;
   let cc = cc.as_many().context(location_info!())?;
-  let community_followers_uri = cc
+  let community_uri = cc
     .first()
     .context(location_info!())?
     .as_xsd_any_uri()
     .context(location_info!())?;
-  // TODO: this is hacky but seems to be the only way to get the community ID
-  let community_uri = community_followers_uri
-    .to_string()
-    .replace("/followers", "");
-  let community = get_or_fetch_and_upsert_community(&Url::parse(&community_uri)?, context).await?;
+  let community = get_or_fetch_and_upsert_community(&community_uri, context).await?;
 
   if community.local {
     community
@@ -71,6 +70,7 @@ where
   Ok(())
 }
 
+/// Reads the actor field of an activity and returns the corresponding `User_`.
 pub(crate) async fn get_actor_as_user<T, A>(
   activity: &T,
   context: &LemmyContext,
@@ -89,6 +89,9 @@ pub(crate) enum FindResults {
   Post(Post),
 }
 
+/// Tries to find a community, post or comment in the local database, without any network requests.
+/// This is used to handle deletions and removals, because in case we dont have the object, we can
+/// simply ignore the activity.
 pub(crate) async fn find_by_id(
   context: &LemmyContext,
   apub_id: Url,
@@ -123,6 +126,11 @@ pub(crate) async fn find_by_id(
   return Err(NotFound.into());
 }
 
+/// Ensure that the ID of an incoming activity comes from the same domain as the actor. Optionally
+/// also checks the ID of the inner object.
+///
+/// The reason that this starts with the actor ID is that it was already confirmed as correct by the
+/// HTTP signature.
 pub(crate) fn verify_activity_domains_valid<T, Kind>(
   activity: &T,
   actor_id: Url,
index bbf3adb17f170b97a53d008c9ab941e6cc840111..bcfd779c8d73c8e6513e9a22386535b81a12fd52 100644 (file)
@@ -41,7 +41,8 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ApubObjectType for Comment {
-  /// Send out information about a newly created comment, to the followers of the community.
+  /// Send out information about a newly created comment, to the followers of the community and
+  /// mentioned users.
   async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let note = self.to_apub(context.pool()).await?;
 
@@ -68,12 +69,13 @@ impl ApubObjectType for Comment {
       // Set the mention tags
       .set_many_tags(maa.get_tags()?);
 
-    send_to_community(&creator, &community, create.clone(), context).await?;
+    send_to_community(create.clone(), &creator, &community, context).await?;
     send_comment_mentions(&creator, maa.inboxes, create, context).await?;
     Ok(())
   }
 
-  /// Send out information about an edited post, to the followers of the community.
+  /// Send out information about an edited post, to the followers of the community and mentioned
+  /// users.
   async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let note = self.to_apub(context.pool()).await?;
 
@@ -100,7 +102,7 @@ impl ApubObjectType for Comment {
       // Set the mention tags
       .set_many_tags(maa.get_tags()?);
 
-    send_to_community(&creator, &community, update.clone(), context).await?;
+    send_to_community(update.clone(), &creator, &community, context).await?;
     send_comment_mentions(&creator, maa.inboxes, update, context).await?;
     Ok(())
   }
@@ -122,7 +124,7 @@ impl ApubObjectType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, delete, context).await?;
+    send_to_community(delete, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -156,7 +158,7 @@ impl ApubObjectType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, undo, context).await?;
+    send_to_community(undo, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -177,7 +179,7 @@ impl ApubObjectType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&mod_, &community, remove, context).await?;
+    send_to_community(remove, &mod_, &community, context).await?;
     Ok(())
   }
 
@@ -207,7 +209,7 @@ impl ApubObjectType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&mod_, &community, undo, context).await?;
+    send_to_community(undo, &mod_, &community, context).await?;
     Ok(())
   }
 }
@@ -233,7 +235,7 @@ impl ApubLikeableType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, like, context).await?;
+    send_to_community(like, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -256,7 +258,7 @@ impl ApubLikeableType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, dislike, context).await?;
+    send_to_community(dislike, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -291,7 +293,7 @@ impl ApubLikeableType for Comment {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, undo, context).await?;
+    send_to_community(undo, &creator, &community, context).await?;
     Ok(())
   }
 }
index 3bed1a2ae9626e781db9a76e53270961f6fe496b..2f43f9c55f618d41bc48d6a62568e843c1b67296 100644 (file)
@@ -84,6 +84,7 @@ impl ActorType for Community {
     Ok(())
   }
 
+  /// If the creator of a community deletes the community, send this to all followers.
   async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let group = self.to_apub(context.pool()).await?;
 
@@ -98,6 +99,7 @@ impl ActorType for Community {
     Ok(())
   }
 
+  /// If the creator of a community reverts the deletion of a community, send this to all followers.
   async fn send_undo_delete(
     &self,
     creator: &User_,
@@ -123,6 +125,7 @@ impl ActorType for Community {
     Ok(())
   }
 
+  /// If an admin removes a community, send this to all followers.
   async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?);
     remove
@@ -135,6 +138,7 @@ impl ActorType for Community {
     Ok(())
   }
 
+  /// If an admin reverts the removal of a community, send this to all followers.
   async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?);
     remove
@@ -155,6 +159,8 @@ impl ActorType for Community {
     Ok(())
   }
 
+  /// Wraps an activity sent to the community in an announce, and then sends the announce to all
+  /// community followers.
   async fn send_announce(
     &self,
     activity: AnyBase,
index 22cc10f4a296c4491867dc4059a84b7994589911..fe898bd8f2ee795b426760db5a382bdead167f06 100644 (file)
@@ -8,6 +8,8 @@ pub mod post;
 pub mod private_message;
 pub mod user;
 
+/// Generate a unique ID for an activity, in the format:
+/// `http(s)://example.com/receive/create/202daf0a-1489-45df-8d2e-c8a3173fed36`
 fn generate_activity_id<T>(kind: T) -> Result<Url, ParseError>
 where
   T: ToString,
index 568a5f5716192fca023408d82e57d75dc18d6411..32035952d1f8f28662d03b18d61cb48cfc369d51 100644 (file)
@@ -45,7 +45,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(creator, &community, create, context).await?;
+    send_to_community(create, creator, &community, context).await?;
     Ok(())
   }
 
@@ -66,7 +66,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(creator, &community, update, context).await?;
+    send_to_community(update, creator, &community, context).await?;
     Ok(())
   }
 
@@ -84,7 +84,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(creator, &community, delete, context).await?;
+    send_to_community(delete, creator, &community, context).await?;
     Ok(())
   }
 
@@ -114,7 +114,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(creator, &community, undo, context).await?;
+    send_to_community(undo, creator, &community, context).await?;
     Ok(())
   }
 
@@ -132,7 +132,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(mod_, &community, remove, context).await?;
+    send_to_community(remove, mod_, &community, context).await?;
     Ok(())
   }
 
@@ -158,7 +158,7 @@ impl ApubObjectType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(mod_, &community, undo, context).await?;
+    send_to_community(undo, mod_, &community, context).await?;
     Ok(())
   }
 }
@@ -181,7 +181,7 @@ impl ApubLikeableType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, like, context).await?;
+    send_to_community(like, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -201,7 +201,7 @@ impl ApubLikeableType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, dislike, context).await?;
+    send_to_community(dislike, &creator, &community, context).await?;
     Ok(())
   }
 
@@ -233,7 +233,7 @@ impl ApubLikeableType for Post {
       .set_to(public())
       .set_many_ccs(vec![community.actor_id()?]);
 
-    send_to_community(&creator, &community, undo, context).await?;
+    send_to_community(undo, &creator, &community, context).await?;
     Ok(())
   }
 }
index 89b6540416d11cb1d1a504eef51c42bade5ad7c3..51d140293bc5702d71522d5976b0883fc04c0358 100644 (file)
@@ -41,7 +41,7 @@ impl ApubObjectType for PrivateMessage {
     Ok(())
   }
 
-  /// Send out information about an edited post, to the followers of the community.
+  /// Send out information about an edited private message, to the followers of the community.
   async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
     let note = self.to_apub(context.pool()).await?;
 
index 715c530449f7f7045a0bd5c0eae3b35634aaee58..839cf667f3f62e9c030b42882718bdb90e76ac9a 100644 (file)
@@ -28,6 +28,11 @@ use serde::{export::fmt::Debug, Deserialize, Serialize};
 use std::{collections::BTreeMap, future::Future, pin::Pin};
 use url::Url;
 
+/// Sends a local activity to a single, remote actor.
+///
+/// * `activity` the apub activity to be sent
+/// * `creator` the local actor which created the activity
+/// * `inbox` the inbox url where the activity should be delivered to
 pub async fn send_activity_single_dest<T, Kind>(
   activity: T,
   creator: &dyn ActorType,
@@ -59,6 +64,12 @@ where
   Ok(())
 }
 
+/// From a local community, send activity to all remote followers.
+///
+/// * `activity` the apub activity to send
+/// * `community` the sending community
+/// * `sender_shared_inbox` in case of an announce, this should be the shared inbox of the inner
+///                         activities creator, as receiving a known activity will cause an error
 pub async fn send_to_community_followers<T, Kind>(
   activity: T,
   community: &Community,
@@ -102,10 +113,16 @@ where
   Ok(())
 }
 
+/// Sends an activity from a local user to a remote community.
+///
+/// * `activity` the activity to send
+/// * `creator` the creator of the activity
+/// * `community` the destination community
+///
 pub async fn send_to_community<T, Kind>(
+  activity: T,
   creator: &User_,
   community: &Community,
-  activity: T,
   context: &LemmyContext,
 ) -> Result<(), LemmyError>
 where
@@ -140,6 +157,11 @@ where
   Ok(())
 }
 
+/// Sends notification to any users mentioned in a comment
+///
+/// * `creator` user who created the comment
+/// * `mentions` list of inboxes of users which are mentioned in the comment
+/// * `activity` either a `Create/Note` or `Update/Note`
 pub async fn send_comment_mentions<T, Kind>(
   creator: &User_,
   mentions: Vec<Url>,
@@ -173,7 +195,8 @@ where
   Ok(())
 }
 
-/// Asynchronously sends the given `activity` from `actor` to every inbox URL in `to`.
+/// Create new `SendActivityTasks`, which will deliver the given activity to inboxes, as well as
+/// handling signing and retrying failed deliveres.
 ///
 /// The caller of this function needs to remove any blocked domains from `to`,
 /// using `check_is_apub_id_valid()`.
@@ -224,6 +247,8 @@ struct SendActivityTask {
   private_key: String,
 }
 
+/// Signs the activity with the sending actor's key, and delivers to the given inbox. Also retries
+/// if the delivery failed.
 impl ActixJob for SendActivityTask {
   type State = MyState;
   type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
index 766b3d796559988f4235f4728b1222da6681dba0..cb15267200828ffe3001a3f1b410433b5868fdd8 100644 (file)
@@ -5,6 +5,8 @@ use lemmy_db::{category::Category, Crud};
 use lemmy_utils::LemmyError;
 use serde::{Deserialize, Serialize};
 
+/// Activitystreams extension to allow (de)serializing additional Community fields `category` and
+/// `sensitive` (called 'nsfw' in Lemmy).
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct GroupExtension {
index aa3d01604dd2592609e6d479746ef6d306c02f0f..8ed12a0c7f268f3a681f973e05ed0fc026f09e3c 100644 (file)
@@ -2,6 +2,9 @@ use activitystreams::unparsed::UnparsedMutExt;
 use activitystreams_ext::UnparsedExtension;
 use serde::{Deserialize, Serialize};
 
+/// Activitystreams extension to allow (de)serializing additional Post fields
+/// `comemnts_enabled` (called 'locked' in Lemmy),
+/// `sensitive` (called 'nsfw') and `stickied`.
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct PageExtension {
index 8e8c31e4dab05e86e60b3c96e219a56ec7828d8c..6ff61df4598f20b669a217b4367cb9f45d524ada 100644 (file)
@@ -24,11 +24,12 @@ lazy_static! {
   static ref HTTP_SIG_CONFIG: Config = Config::new();
 }
 
-/// Signs request headers with the given keypair.
+/// Creates an HTTP post request to `inbox_url`, with the given `client` and `headers`, and
+/// `activity` as request body. The request is signed with `private_key` and then sent.
 pub async fn sign_and_send(
   client: &Client,
   headers: BTreeMap<String, String>,
-  url: &Url,
+  inbox_url: &Url,
   activity: String,
   actor_id: &Url,
   private_key: String,
@@ -43,7 +44,7 @@ pub async fn sign_and_send(
     );
   }
   let response = client
-    .post(&url.to_string())
+    .post(&inbox_url.to_string())
     .headers(header_map)
     .signature_with_digest(
       HTTP_SIG_CONFIG.clone(),
@@ -63,6 +64,7 @@ pub async fn sign_and_send(
   Ok(response)
 }
 
+/// Verifies the HTTP signature on an incoming inbox request.
 pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
   let public_key = actor.public_key().context(location_info!())?;
   let verified = CONFIG2
@@ -90,8 +92,14 @@ pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<
   }
 }
 
-// The following is taken from here:
-// https://docs.rs/activitystreams/0.5.0-alpha.17/activitystreams/ext/index.html
+/// Extension for actor public key, which is needed on user and community for HTTP signatures.
+///
+/// Taken from: https://docs.rs/activitystreams/0.5.0-alpha.17/activitystreams/ext/index.html
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PublicKeyExtension {
+  pub public_key: PublicKey,
+}
 
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
@@ -101,12 +109,6 @@ pub struct PublicKey {
   pub public_key_pem: String,
 }
 
-#[derive(Clone, Debug, Default, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct PublicKeyExtension {
-  pub public_key: PublicKey,
-}
-
 impl PublicKey {
   pub fn to_ext(&self) -> PublicKeyExtension {
     PublicKeyExtension {
index 986c9dd470ac93396715b25be56e351a1401c64c..908d1a5eacbbcc3f41df8fa7983c4afe87b2289b 100644 (file)
@@ -82,11 +82,11 @@ pub enum SearchAcceptedObjects {
 
 /// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
 ///
-/// Some working examples for use with the docker/federation/ setup:
-/// http://lemmy_alpha:8540/c/main, or !main@lemmy_alpha:8540
-/// http://lemmy_alpha:8540/u/lemmy_alpha, or @lemmy_alpha@lemmy_alpha:8540
-/// http://lemmy_alpha:8540/post/3
-/// http://lemmy_alpha:8540/comment/2
+/// Some working examples for use with the `docker/federation/` setup:
+/// http://lemmy_alpha:8541/c/main, or !main@lemmy_alpha:8541
+/// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551
+/// http://lemmy_gamma:8561/post/3
+/// http://lemmy_delta:8571/comment/2
 pub async fn search_by_apub_id(
   query: &str,
   context: &LemmyContext,
@@ -191,19 +191,27 @@ pub async fn search_by_apub_id(
   Ok(response)
 }
 
+/// Get a remote actor from its apub ID (either a user or a community). Thin wrapper around
+/// `get_or_fetch_and_upsert_user()` and `get_or_fetch_and_upsert_community()`.
+///
+/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
+/// Otherwise it is fetched from the remote instance, stored and returned.
 pub(crate) async fn get_or_fetch_and_upsert_actor(
   apub_id: &Url,
   context: &LemmyContext,
 ) -> Result<Box<dyn ActorType>, LemmyError> {
-  let user = get_or_fetch_and_upsert_user(apub_id, context).await;
-  let actor: Box<dyn ActorType> = match user {
-    Ok(u) => Box::new(u),
-    Err(_) => Box::new(get_or_fetch_and_upsert_community(apub_id, context).await?),
+  let community = get_or_fetch_and_upsert_community(apub_id, context).await;
+  let actor: Box<dyn ActorType> = match community {
+    Ok(c) => Box::new(c),
+    Err(_) => Box::new(get_or_fetch_and_upsert_user(apub_id, context).await?),
   };
   Ok(actor)
 }
 
-/// Check if a remote user exists, create if not found, if its too old update it.Fetch a user, insert/update it in the database and return the user.
+/// Get a user from its apub ID.
+///
+/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
+/// Otherwise it is fetched from the remote instance, stored and returned.
 pub(crate) async fn get_or_fetch_and_upsert_user(
   apub_id: &Url,
   context: &LemmyContext,
@@ -241,7 +249,8 @@ pub(crate) async fn get_or_fetch_and_upsert_user(
 }
 
 /// Determines when a remote actor should be refetched from its instance. In release builds, this is
-/// ACTOR_REFETCH_INTERVAL_SECONDS after the last refetch, in debug builds always.
+/// `ACTOR_REFETCH_INTERVAL_SECONDS` after the last refetch, in debug builds
+/// `ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG`.
 ///
 /// TODO it won't pick up new avatars, summaries etc until a day after.
 /// Actors need an "update" activity pushed to other servers to fix this.
@@ -255,7 +264,10 @@ fn should_refetch_actor(last_refreshed: NaiveDateTime) -> bool {
   last_refreshed.lt(&(naive_now() - update_interval))
 }
 
-/// Check if a remote community exists, create if not found, if its too old update it.Fetch a community, insert/update it in the database and return the community.
+/// Get a community from its apub ID.
+///
+/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
+/// Otherwise it is fetched from the remote instance, stored and returned.
 pub(crate) async fn get_or_fetch_and_upsert_community(
   apub_id: &Url,
   context: &LemmyContext,
@@ -280,6 +292,9 @@ pub(crate) async fn get_or_fetch_and_upsert_community(
   }
 }
 
+/// Request a community by apub ID from a remote instance, including moderators. If `community_id`,
+/// is set, this is an update for a community which is already known locally. If not, we don't know
+/// the community yet and also pull the outbox, to get some initial posts.
 async fn fetch_remote_community(
   apub_id: &Url,
   context: &LemmyContext,
@@ -358,6 +373,10 @@ async fn fetch_remote_community(
   Ok(community)
 }
 
+/// Gets a post by its apub ID. If it exists locally, it is returned directly. Otherwise it is
+/// pulled from its apub ID, inserted and returned.
+///
+/// The parent community is also pulled if necessary. Comments are not pulled.
 pub(crate) async fn get_or_fetch_and_insert_post(
   post_ap_id: &Url,
   context: &LemmyContext,
@@ -383,6 +402,10 @@ pub(crate) async fn get_or_fetch_and_insert_post(
   }
 }
 
+/// Gets a comment by its apub ID. If it exists locally, it is returned directly. Otherwise it is
+/// pulled from its apub ID, inserted and returned.
+///
+/// The parent community, post and comment are also pulled if necessary.
 pub(crate) async fn get_or_fetch_and_insert_comment(
   comment_ap_id: &Url,
   context: &LemmyContext,
index 040be2b037a420774f54ce0f69a7a0bb09131ade..936cd98138160dd653e3f67fccb1615c9ed1d011 100644 (file)
@@ -15,7 +15,7 @@ pub struct CommentQuery {
   comment_id: String,
 }
 
-/// Return the post json over HTTP.
+/// Return the ActivityPub json representation of a local comment over HTTP.
 pub async fn get_apub_comment(
   info: Path<CommentQuery>,
   context: web::Data<LemmyContext>,
index 0559536ba427c432b2fe2bf92a7c2a0f09b656fa..bd9c86fea613f4bc2a8068564a48ee5e8155c19f 100644 (file)
@@ -19,7 +19,7 @@ pub struct CommunityQuery {
   community_name: String,
 }
 
-/// Return the community json over HTTP.
+/// Return the ActivityPub json representation of a local community over HTTP.
 pub async fn get_apub_community_http(
   info: web::Path<CommunityQuery>,
   context: web::Data<LemmyContext>,
@@ -62,6 +62,8 @@ pub async fn get_apub_community_followers(
   Ok(create_apub_response(&collection))
 }
 
+/// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
+/// activites like votes or comments).
 pub async fn get_apub_community_outbox(
   info: web::Path<CommunityQuery>,
   context: web::Data<LemmyContext>,
index b3dd8ce8953f6f8df74b1c53ef2b6ae1901af1a7..7f4bb447cc915221700a2055093e3e026de53976 100644 (file)
@@ -15,7 +15,7 @@ pub struct PostQuery {
   post_id: String,
 }
 
-/// Return the post json over HTTP.
+/// Return the ActivityPub json representation of a local post over HTTP.
 pub async fn get_apub_post(
   info: web::Path<PostQuery>,
   context: web::Data<LemmyContext>,
index 9158eede34b67caf6374cc7642463efa66c01be8..85a5f22ccf62bccee3b4906cc4596a5ce61e6e52 100644 (file)
@@ -11,7 +11,7 @@ pub struct UserQuery {
   user_name: String,
 }
 
-/// Return the user json over HTTP.
+/// Return the ActivityPub json representation of a local user over HTTP.
 pub async fn get_apub_user_http(
   info: web::Path<UserQuery>,
   context: web::Data<LemmyContext>,
index 2c36c684089bef0eb1ab4c4361c4f3b0308641cc..11d09972b5392ae6f7c2ccece8746147f51f956a 100644 (file)
@@ -25,6 +25,7 @@ use log::info;
 use serde::{Deserialize, Serialize};
 use std::fmt::Debug;
 
+/// Allowed activities for community inbox.
 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
 #[serde(rename_all = "PascalCase")]
 pub enum ValidTypes {
@@ -90,7 +91,7 @@ pub async fn community_inbox(
   res
 }
 
-/// Handle a follow request from a remote user, adding it to the local database and returning an
+/// Handle a follow request from a remote user, adding the user as follower and returning an
 /// Accept activity.
 async fn handle_follow(
   activity: AnyBase,
@@ -117,6 +118,7 @@ async fn handle_follow(
   Ok(HttpResponse::Ok().finish())
 }
 
+/// Handle `Undo/Follow` from a user, removing the user from followers list.
 async fn handle_undo_follow(
   activity: AnyBase,
   user: User_,
index d705680613c5d1c5af2f4ae52ed4f78f09942eea..f3a1177eb6b4fba7a158e529cf88254cf7f24d80 100644 (file)
@@ -23,6 +23,7 @@ use log::debug;
 use serde::{Deserialize, Serialize};
 use std::fmt::Debug;
 
+/// Allowed activity types for shared inbox.
 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
 #[serde(rename_all = "PascalCase")]
 pub enum ValidTypes {
@@ -40,7 +41,7 @@ pub enum ValidTypes {
 //       but it might still work due to the anybase conversion
 pub type AcceptedActivities = ActorAndObject<ValidTypes>;
 
-/// Handler for all incoming receive to user inboxes.
+/// Handler for all incoming requests to shared inbox.
 pub async fn shared_inbox(
   request: HttpRequest,
   input: web::Json<AcceptedActivities>,
index 2ee6d6edf46e86172c1f9dc0ac1a7c761a46e3b3..ebb11a56e3ca6f0056b06c681a24a8d6ee92ed94 100644 (file)
@@ -30,6 +30,7 @@ use log::debug;
 use serde::{Deserialize, Serialize};
 use std::fmt::Debug;
 
+/// Allowed activities for user inbox.
 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
 #[serde(rename_all = "PascalCase")]
 pub enum ValidTypes {
@@ -42,7 +43,7 @@ pub enum ValidTypes {
 
 pub type AcceptedActivities = ActorAndObject<ValidTypes>;
 
-/// Handler for all incoming receive to user inboxes.
+/// Handler for all incoming activities to user inboxes.
 pub async fn user_inbox(
   request: HttpRequest,
   input: web::Json<AcceptedActivities>,
index 4c8f962207c45c36a28ea39d853a647f27131679..c93d6477c3cecd3e38c2bedff462546795066760 100644 (file)
@@ -29,13 +29,24 @@ use lemmy_websocket::LemmyContext;
 use serde::Serialize;
 use url::{ParseError, Url};
 
+/// Activitystreams type for community
 type GroupExt = Ext2<ApActor<Group>, GroupExtension, PublicKeyExtension>;
+/// Activitystreams type for user
 type PersonExt = Ext1<ApActor<Person>, PublicKeyExtension>;
+/// Activitystreams type for post
 type PageExt = Ext1<Page, PageExtension>;
 
 pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
 
-// Checks if the ID has a valid format, correct scheme, and is in the allowed instance list.
+/// Checks if the ID is allowed for sending or receiving.
+///
+/// In particular, it checks for:
+/// - federation being enabled (if its disabled, only local URLs are allowed)
+/// - the correct scheme (either http or https)
+/// - URL being in the allowlist (if it is active)
+/// - URL not being in the blocklist (if it is active)
+///
+/// Note that only one of allowlist and blacklist can be enabled, not both.
 fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
   let settings = Settings::get();
   let domain = apub_id.domain().context(location_info!())?.to_string();
@@ -90,10 +101,11 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
   }
 }
 
+/// Trait for converting an object or actor into the respective ActivityPub type.
 #[async_trait::async_trait(?Send)]
 pub trait ToApub {
-  type Response;
-  async fn to_apub(&self, pool: &DbPool) -> Result<Self::Response, LemmyError>;
+  type ApubType;
+  async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
   fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
 }
 
@@ -104,9 +116,8 @@ pub trait FromApub {
   ///
   /// * `apub` The object to read from
   /// * `context` LemmyContext which holds DB pool, HTTP client etc
-  /// * `expected_domain` If present, ensure that the apub object comes from the same domain as
-  ///                     this URL
-  ///
+  /// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are
+  ///                     identical
   async fn from_apub(
     apub: &Self::ApubType,
     context: &LemmyContext,
@@ -116,6 +127,8 @@ pub trait FromApub {
     Self: Sized;
 }
 
+/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
+/// and actors in Lemmy.
 #[async_trait::async_trait(?Send)]
 pub trait ApubObjectType {
   async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>;
@@ -138,6 +151,8 @@ pub trait ApubLikeableType {
     -> Result<(), LemmyError>;
 }
 
+/// Common methods provided by ActivityPub actors (community and user). Not all methods are
+/// implemented by all actors.
 #[async_trait::async_trait(?Send)]
 pub trait ActorType {
   fn actor_id_str(&self) -> String;
@@ -149,9 +164,6 @@ pub trait ActorType {
   /// numeric id in the database, used for insert_activity
   fn user_id(&self) -> i32;
 
-  // These two have default impls, since currently a community can't follow anything,
-  // and a user can't be followed (yet)
-  #[allow(unused_variables)]
   async fn send_follow(
     &self,
     follow_actor_id: &Url,
@@ -163,7 +175,6 @@ pub trait ActorType {
     context: &LemmyContext,
   ) -> Result<(), LemmyError>;
 
-  #[allow(unused_variables)]
   async fn send_accept_follow(
     &self,
     follow: Follow,
@@ -234,6 +245,8 @@ pub trait ActorType {
   }
 }
 
+/// Store a sent or received activity in the database, for logging purposes. These records are not
+/// persistent.
 pub async fn insert_activity<T>(
   user_id: i32,
   data: T,
index 537ab958e7d4077a3947438a866dc5c7ab224a53..efd2064d67cffd965617a6c7f47304c4dce831ce 100644 (file)
@@ -32,7 +32,7 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ToApub for Comment {
-  type Response = Note;
+  type ApubType = Note;
 
   async fn to_apub(&self, pool: &DbPool) -> Result<Note, LemmyError> {
     let mut comment = Note::new();
@@ -82,7 +82,9 @@ impl ToApub for Comment {
 impl FromApub for CommentForm {
   type ApubType = Note;
 
-  /// Parse an ActivityPub note received from another instance into a Lemmy comment
+  /// Converts a `Note` to `CommentForm`.
+  ///
+  /// If the parent community, post and comment(s) are not known locally, these are also fetched.
   async fn from_apub(
     note: &Note,
     context: &LemmyContext,
index 6a4b1ee5cdd6a02ddab96aa79cce1dece2ef5c58..f6289f267f175440ed56ba6c834b29e3169e3828 100644 (file)
@@ -32,9 +32,8 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ToApub for Community {
-  type Response = GroupExt;
+  type ApubType = GroupExt;
 
-  // Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
   async fn to_apub(&self, pool: &DbPool) -> Result<GroupExt, LemmyError> {
     // The attributed to, is an ordered vector with the creator actor_ids first,
     // then the rest of the moderators
@@ -108,7 +107,6 @@ impl ToApub for Community {
 impl FromApub for CommunityForm {
   type ApubType = GroupExt;
 
-  /// Parse an ActivityPub group received from another instance into a Lemmy community.
   async fn from_apub(
     group: &GroupExt,
     context: &LemmyContext,
index 157dcbe275edf816643d17e640bbb1934941c117..8796146d52e0cc65b60cc483e2ddeaaa17632363 100644 (file)
@@ -31,7 +31,7 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ToApub for Post {
-  type Response = PageExt;
+  type ApubType = PageExt;
 
   // Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
   async fn to_apub(&self, pool: &DbPool) -> Result<PageExt, LemmyError> {
@@ -94,7 +94,9 @@ impl ToApub for Post {
 impl FromApub for PostForm {
   type ApubType = PageExt;
 
-  /// Parse an ActivityPub page received from another instance into a Lemmy post.
+  /// Converts a `PageExt` to `PostForm`.
+  ///
+  /// If the post's community or creator are not known locally, these are also fetched.
   async fn from_apub(
     page: &PageExt,
     context: &LemmyContext,
index 413ab22f4a10a3301128f05bb976b83d2ee758f1..119dfb56c2c970182b59e22088fca04d31d3ab68 100644 (file)
@@ -23,7 +23,7 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ToApub for PrivateMessage {
-  type Response = Note;
+  type ApubType = Note;
 
   async fn to_apub(&self, pool: &DbPool) -> Result<Note, LemmyError> {
     let mut private_message = Note::new();
@@ -58,7 +58,6 @@ impl ToApub for PrivateMessage {
 impl FromApub for PrivateMessageForm {
   type ApubType = Note;
 
-  /// Parse an ActivityPub note received from another instance into a Lemmy Private message
   async fn from_apub(
     note: &Note,
     context: &LemmyContext,
index 944f7c1dac7aeeda4211f7465aef3875dd989d1d..b1f660b175ee0c489e3d3df8865c055e0a2e4925 100644 (file)
@@ -21,11 +21,9 @@ use url::Url;
 
 #[async_trait::async_trait(?Send)]
 impl ToApub for User_ {
-  type Response = PersonExt;
+  type ApubType = PersonExt;
 
-  // Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
   async fn to_apub(&self, _pool: &DbPool) -> Result<PersonExt, LemmyError> {
-    // TODO go through all these to_string and to_owned()
     let mut person = Person::new();
     person
       .set_context(activitystreams::context())
@@ -73,7 +71,7 @@ impl ToApub for User_ {
 #[async_trait::async_trait(?Send)]
 impl FromApub for UserForm {
   type ApubType = PersonExt;
-  /// Parse an ActivityPub person received from another instance into a Lemmy user.
+
   async fn from_apub(
     person: &PersonExt,
     _context: &LemmyContext,