diff options
Diffstat (limited to 'server/src/apub')
-rw-r--r-- | server/src/apub/activities.rs | 12 | ||||
-rw-r--r-- | server/src/apub/comment.rs | 20 | ||||
-rw-r--r-- | server/src/apub/community.rs | 220 | ||||
-rw-r--r-- | server/src/apub/community_inbox.rs | 12 | ||||
-rw-r--r-- | server/src/apub/extensions/group_extensions.rs | 6 | ||||
-rw-r--r-- | server/src/apub/extensions/signatures.rs | 18 | ||||
-rw-r--r-- | server/src/apub/fetcher.rs | 110 | ||||
-rw-r--r-- | server/src/apub/mod.rs | 78 | ||||
-rw-r--r-- | server/src/apub/post.rs | 18 | ||||
-rw-r--r-- | server/src/apub/private_message.rs | 16 | ||||
-rw-r--r-- | server/src/apub/shared_inbox.rs | 117 | ||||
-rw-r--r-- | server/src/apub/user.rs | 124 | ||||
-rw-r--r-- | server/src/apub/user_inbox.rs | 36 |
13 files changed, 374 insertions, 413 deletions
diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs index e5dc7045..204a380d 100644 --- a/server/src/apub/activities.rs +++ b/server/src/apub/activities.rs @@ -1,12 +1,18 @@ use crate::{ - apub::{extensions::signatures::sign, is_apub_id_valid, ActorType}, - db::{activity::insert_activity, community::Community, user::User_}, + apub::{ + community::do_announce, + extensions::signatures::sign, + insert_activity, + is_apub_id_valid, + ActorType, + }, request::retry_custom, DbPool, LemmyError, }; use activitystreams::{context, object::properties::ObjectProperties, public, Activity, Base}; use actix_web::client::Client; +use lemmy_db::{community::Community, user::User_}; use log::debug; use serde::Serialize; use std::fmt::Debug; @@ -43,7 +49,7 @@ where // if this is a local community, we need to do an announce from the community instead if community.local { - Community::do_announce(activity, &community, creator, client, pool).await?; + do_announce(activity, &community, creator, client, pool).await?; } else { send_activity(client, &activity, creator, to).await?; } diff --git a/server/src/apub/comment.rs b/server/src/apub/comment.rs index a42a52c2..af3581cb 100644 --- a/server/src/apub/comment.rs +++ b/server/src/apub/comment.rs @@ -17,19 +17,9 @@ use crate::{ ToApub, }, blocking, - convert_datetime, - db::{ - comment::{Comment, CommentForm}, - community::Community, - post::Post, - user::User_, - Crud, - }, routes::DbPoolParam, - scrape_text_for_mentions, DbPool, LemmyError, - MentionData, }; use activitystreams::{ activity::{Create, Delete, Dislike, Like, Remove, Undo, Update}, @@ -40,6 +30,14 @@ use activitystreams::{ use activitystreams_new::object::Tombstone; use actix_web::{body::Body, client::Client, web::Path, HttpResponse}; use itertools::Itertools; +use lemmy_db::{ + comment::{Comment, CommentForm}, + community::Community, + post::Post, + user::User_, + Crud, +}; +use lemmy_utils::{convert_datetime, scrape_text_for_mentions, MentionData}; use log::debug; use serde::Deserialize; @@ -123,7 +121,7 @@ impl FromApub for CommentForm { /// Parse an ActivityPub note received from another instance into a Lemmy comment async fn from_apub( - note: &Note, + note: &mut Note, client: &Client, pool: &DbPool, ) -> Result<CommentForm, LemmyError> { diff --git a/server/src/apub/community.rs b/server/src/apub/community.rs index f866511c..8b623e71 100644 --- a/server/src/apub/community.rs +++ b/server/src/apub/community.rs @@ -4,44 +4,48 @@ use crate::{ create_apub_response, create_apub_tombstone_response, create_tombstone, - extensions::{group_extensions::GroupExtension, signatures::PublicKey}, + extensions::group_extensions::GroupExtension, fetcher::get_or_fetch_and_upsert_remote_user, get_shared_inbox, + insert_activity, ActorType, FromApub, GroupExt, ToApub, }, blocking, - convert_datetime, - db::{ - activity::insert_activity, - community::{Community, CommunityForm}, - community_view::{CommunityFollowerView, CommunityModeratorView}, - user::User_, - }, - naive_now, routes::DbPoolParam, DbPool, LemmyError, }; use activitystreams::{ activity::{Accept, Announce, Delete, Remove, Undo}, - actor::{kind::GroupType, properties::ApActorProperties, Group}, - collection::UnorderedCollection, - context, - endpoint::EndpointProperties, - object::properties::ObjectProperties, Activity, Base, BaseBox, }; -use activitystreams_ext::Ext3; -use activitystreams_new::{activity::Follow, object::Tombstone}; +use activitystreams_ext::Ext2; +use activitystreams_new::{ + activity::Follow, + actor::{kind::GroupType, ApActor, Endpoints, Group}, + base::BaseExt, + collection::UnorderedCollection, + context, + object::Tombstone, + prelude::*, + primitives::{XsdAnyUri, XsdDateTime}, +}; use actix_web::{body::Body, client::Client, web, HttpResponse}; use itertools::Itertools; +use lemmy_db::{ + community::{Community, CommunityForm}, + community_view::{CommunityFollowerView, CommunityModeratorView}, + naive_now, + user::User_, +}; +use lemmy_utils::convert_datetime; use serde::{Deserialize, Serialize}; -use std::fmt::Debug; +use std::{fmt::Debug, str::FromStr}; #[derive(Deserialize)] pub struct CommunityQuery { @@ -54,9 +58,6 @@ impl ToApub for Community { // 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> { - let mut group = Group::default(); - let oprops: &mut ObjectProperties = group.as_mut(); - // The attributed to, is an ordered vector with the creator actor_ids first, // then the rest of the moderators // TODO Technically the instance admins can mod the community, but lets @@ -66,36 +67,36 @@ impl ToApub for Community { CommunityModeratorView::for_community(&conn, id) }) .await??; - let moderators = moderators.into_iter().map(|m| m.user_actor_id).collect(); + let moderators: Vec<String> = moderators.into_iter().map(|m| m.user_actor_id).collect(); - oprops - .set_context_xsd_any_uri(context())? - .set_id(self.actor_id.to_owned())? - .set_name_xsd_string(self.name.to_owned())? - .set_published(convert_datetime(self.published))? - .set_many_attributed_to_xsd_any_uris(moderators)?; + let mut group = Group::new(); + group + .set_context(context()) + .set_id(XsdAnyUri::from_str(&self.actor_id)?) + .set_name(self.name.to_owned()) + .set_published(XsdDateTime::from(convert_datetime(self.published))) + .set_many_attributed_tos(moderators); if let Some(u) = self.updated.to_owned() { - oprops.set_updated(convert_datetime(u))?; + group.set_updated(XsdDateTime::from(convert_datetime(u))); } if let Some(d) = self.description.to_owned() { // TODO: this should be html, also add source field with raw markdown // -> same for post.content and others - oprops.set_content_xsd_string(d)?; + group.set_content(d); } - let mut endpoint_props = EndpointProperties::default(); - - endpoint_props.set_shared_inbox(self.get_shared_inbox_url())?; - - let mut actor_props = ApActorProperties::default(); - - actor_props - .set_preferred_username(self.title.to_owned())? - .set_inbox(self.get_inbox_url())? - .set_outbox(self.get_outbox_url())? - .set_endpoints(endpoint_props)? - .set_followers(self.get_followers_url())?; + let mut ap_actor = ApActor::new(self.get_inbox_url().parse()?, group); + ap_actor + .set_preferred_username(self.title.to_owned()) + .set_outbox(self.get_outbox_url().parse()?) + .set_followers(self.get_followers_url().parse()?) + .set_following(self.get_following_url().parse()?) + .set_liked(self.get_liked_url().parse()?) + .set_endpoints(Endpoints { + shared_inbox: Some(self.get_shared_inbox_url().parse()?), + ..Default::default() + }); let nsfw = self.nsfw; let category_id = self.category_id; @@ -104,10 +105,9 @@ impl ToApub for Community { }) .await??; - Ok(Ext3::new( - group, + Ok(Ext2::new( + ap_actor, group_extension, - actor_props, self.get_public_key_ext(), )) } @@ -367,38 +367,52 @@ 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, client: &Client, pool: &DbPool) -> Result<Self, LemmyError> { - let group_extensions: &GroupExtension = &group.ext_one; - let oprops = &group.inner.object_props; - let aprops = &group.ext_two; - let public_key: &PublicKey = &group.ext_three.public_key; - - let mut creator_and_moderator_uris = oprops.get_many_attributed_to_xsd_any_uris().unwrap(); - let creator_uri = creator_and_moderator_uris.next().unwrap(); + async fn from_apub( + group: &mut GroupExt, + client: &Client, + pool: &DbPool, + ) -> Result<Self, LemmyError> { + // TODO: this is probably gonna cause problems cause fetcher:292 also calls take_attributed_to() + let creator_and_moderator_uris = group.clone().take_attributed_to().unwrap(); + let creator_uri = creator_and_moderator_uris + .as_many() + .unwrap() + .iter() + .next() + .unwrap() + .as_xsd_any_uri() + .unwrap(); let creator = get_or_fetch_and_upsert_remote_user(creator_uri.as_str(), client, pool).await?; Ok(CommunityForm { - name: oprops.get_name_xsd_string().unwrap().to_string(), - title: aprops.get_preferred_username().unwrap().to_string(), + name: group + .take_name() + .unwrap() + .as_single_xsd_string() + .unwrap() + .into(), + title: group.inner.take_preferred_username().unwrap(), // TODO: should be parsed as html and tags like <script> removed (or use markdown source) // -> same for post.content etc - description: oprops.get_content_xsd_string().map(|s| s.to_string()), - category_id: group_extensions.category.identifier.parse::<i32>()?, + description: group + .take_content() + .map(|s| s.as_single_xsd_string().unwrap().into()), + category_id: group.ext_one.category.identifier.parse::<i32>()?, creator_id: creator.id, removed: None, - published: oprops - .get_published() + published: group + .take_published() .map(|u| u.as_ref().to_owned().naive_local()), - updated: oprops - .get_updated() + updated: group + .take_updated() .map(|u| u.as_ref().to_owned().naive_local()), deleted: None, - nsfw: group_extensions.sensitive, - actor_id: oprops.get_id().unwrap().to_string(), + nsfw: group.ext_one.sensitive, + actor_id: group.id().unwrap().to_string(), local: false, private_key: None, - public_key: Some(public_key.to_owned().public_key_pem), + public_key: Some(group.ext_two.to_owned().public_key.public_key_pem), last_refreshed_at: Some(naive_now()), }) } @@ -439,50 +453,46 @@ pub async fn get_apub_community_followers( }) .await??; - let mut collection = UnorderedCollection::default(); - let oprops: &mut ObjectProperties = collection.as_mut(); - oprops - .set_context_xsd_any_uri(context())? - .set_id(community.actor_id)?; + let mut collection = UnorderedCollection::new(vec![]); collection - .collection_props - .set_total_items(community_followers.len() as u64)?; + .set_context(context()) + // TODO: this needs its own ID + .set_id(community.actor_id.parse()?) + .set_total_items(community_followers.len() as u64); Ok(create_apub_response(&collection)) } -impl Community { - pub async fn do_announce<A>( - activity: A, - community: &Community, - sender: &dyn ActorType, - client: &Client, - pool: &DbPool, - ) -> Result<HttpResponse, LemmyError> - where - A: Activity + Base + Serialize + Debug, - { - let mut announce = Announce::default(); - populate_object_props( - &mut announce.object_props, - vec![community.get_followers_url()], - &format!("{}/announce/{}", community.actor_id, uuid::Uuid::new_v4()), - )?; - announce - .announce_props - .set_actor_xsd_any_uri(community.actor_id.to_owned())? - .set_object_base_box(BaseBox::from_concrete(activity)?)?; - - insert_activity(community.creator_id, announce.clone(), true, pool).await?; - - // dont send to the instance where the activity originally came from, because that would result - // in a database error (same data inserted twice) - let mut to = community.get_follower_inboxes(pool).await?; - - // this seems to be the "easiest" stable alternative for remove_item() - to.retain(|x| *x != sender.get_shared_inbox_url()); - - send_activity(client, &announce, community, to).await?; - - Ok(HttpResponse::Ok().finish()) - } +pub async fn do_announce<A>( + activity: A, + community: &Community, + sender: &dyn ActorType, + client: &Client, + pool: &DbPool, +) -> Result<HttpResponse, LemmyError> +where + A: Activity + Base + Serialize + Debug, +{ + let mut announce = Announce::default(); + populate_object_props( + &mut announce.object_props, + vec![community.get_followers_url()], + &format!("{}/announce/{}", community.actor_id, uuid::Uuid::new_v4()), + )?; + announce + .announce_props + .set_actor_xsd_any_uri(community.actor_id.to_owned())? + .set_object_base_box(BaseBox::from_concrete(activity)?)?; + + insert_activity(community.creator_id, announce.clone(), true, pool).await?; + + // dont send to the instance where the activity originally came from, because that would result + // in a database error (same data inserted twice) + let mut to = community.get_follower_inboxes(pool).await?; + + // this seems to be the "easiest" stable alternative for remove_item() + to.retain(|x| *x != sender.get_shared_inbox_url()); + + send_activity(client, &announce, community, to).await?; + + Ok(HttpResponse::Ok().finish()) } diff --git a/server/src/apub/community_inbox.rs b/server/src/apub/community_inbox.rs index 996e0c25..8ea64434 100644 --- a/server/src/apub/community_inbox.rs +++ b/server/src/apub/community_inbox.rs @@ -2,21 +2,21 @@ use crate::{ apub::{ extensions::signatures::verify, fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user}, + insert_activity, ActorType, }, blocking, - db::{ - activity::insert_activity, - community::{Community, CommunityFollower, CommunityFollowerForm}, - user::User_, - Followable, - }, routes::{ChatServerParam, DbPoolParam}, LemmyError, }; use activitystreams::activity::Undo; use activitystreams_new::activity::Follow; use actix_web::{client::Client, web, HttpRequest, HttpResponse}; +use lemmy_db::{ + community::{Community, CommunityFollower, CommunityFollowerForm}, + user::User_, + Followable, +}; use log::debug; use serde::Deserialize; use std::fmt::Debug; diff --git a/server/src/apub/extensions/group_extensions.rs b/server/src/apub/extensions/group_extensions.rs index 1c24eef5..2120f6f1 100644 --- a/server/src/apub/extensions/group_extensions.rs +++ b/server/src/apub/extensions/group_extensions.rs @@ -1,9 +1,7 @@ -use crate::{ - db::{category::Category, Crud}, - LemmyError, -}; +use crate::LemmyError; use activitystreams::{ext::Extension, Actor}; use diesel::PgConnection; +use lemmy_db::{category::Category, Crud}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] diff --git a/server/src/apub/extensions/signatures.rs b/server/src/apub/extensions/signatures.rs index af46bc5e..1c930a95 100644 --- a/server/src/apub/extensions/signatures.rs +++ b/server/src/apub/extensions/signatures.rs @@ -9,7 +9,6 @@ use log::debug; use openssl::{ hash::MessageDigest, pkey::PKey, - rsa::Rsa, sign::{Signer, Verifier}, }; use serde::{Deserialize, Serialize}; @@ -19,23 +18,6 @@ lazy_static! { static ref HTTP_SIG_CONFIG: Config = Config::new(); } -pub struct Keypair { - pub private_key: String, - pub public_key: String, -} - -/// Generate the asymmetric keypair for ActivityPub HTTP signatures. -pub fn generate_actor_keypair() -> Result<Keypair, LemmyError> { - let rsa = Rsa::generate(2048)?; - let pkey = PKey::from_rsa(rsa)?; - let public_key = pkey.public_key_to_pem()?; - let private_key = pkey.private_key_to_pem_pkcs8()?; - Ok(Keypair { - private_key: String::from_utf8(private_key)?, - public_key: String::from_utf8(public_key)?, - }) -} - /// Signs request headers with the given keypair. pub async fn sign( request: ClientRequest, diff --git a/server/src/apub/fetcher.rs b/server/src/apub/fetcher.rs index 598903d0..0604129d 100644 --- a/server/src/apub/fetcher.rs +++ b/server/src/apub/fetcher.rs @@ -1,46 +1,36 @@ -use activitystreams::object::Note; -use actix_web::client::Client; -use diesel::{result::Error::NotFound, PgConnection}; -use log::debug; -use serde::Deserialize; -use std::{fmt::Debug, time::Duration}; -use url::Url; - use crate::{ api::site::SearchResponse, + apub::{is_apub_id_valid, FromApub, GroupExt, PageExt, PersonExt, APUB_JSON_CONTENT_TYPE}, blocking, - db::{ - comment::{Comment, CommentForm}, - comment_view::CommentView, - community::{Community, CommunityForm, CommunityModerator, CommunityModeratorForm}, - community_view::CommunityView, - post::{Post, PostForm}, - post_view::PostView, - user::{UserForm, User_}, - Crud, - Joinable, - SearchType, - }, - naive_now, request::{retry, RecvError}, routes::nodeinfo::{NodeInfo, NodeInfoWellKnown}, DbPool, LemmyError, }; - -use crate::{ - apub::{ - get_apub_protocol_string, - is_apub_id_valid, - FromApub, - GroupExt, - PageExt, - PersonExt, - APUB_JSON_CONTENT_TYPE, - }, - db::user_view::UserView, -}; +use activitystreams::object::Note; +use activitystreams_new::{base::BaseExt, prelude::*, primitives::XsdAnyUri}; +use actix_web::client::Client; use chrono::NaiveDateTime; +use diesel::{result::Error::NotFound, PgConnection}; +use lemmy_db::{ + comment::{Comment, CommentForm}, + comment_view::CommentView, + community::{Community, CommunityForm, CommunityModerator, CommunityModeratorForm}, + community_view::CommunityView, + naive_now, + post::{Post, PostForm}, + post_view::PostView, + user::{UserForm, User_}, + user_view::UserView, + Crud, + Joinable, + SearchType, +}; +use lemmy_utils::get_apub_protocol_string; +use log::debug; +use serde::Deserialize; +use std::{fmt::Debug, time::Duration}; +use url::Url; static ACTOR_REFETCH_INTERVAL_SECONDS: i64 = 24 * 60 * 60; @@ -149,7 +139,7 @@ pub async fn search_by_apub_id( let response = match fetch_remote_object::<SearchAcceptedObjects>(client, &query_url).await? { SearchAcceptedObjects::Person(p) => { - let user_uri = p.inner.object_props.get_id().unwrap().to_string(); + let user_uri = p.inner.id().unwrap().to_string(); let user = get_or_fetch_and_upsert_remote_user(&user_uri, client, pool).await?; @@ -158,7 +148,7 @@ pub async fn search_by_apub_id( response } SearchAcceptedObjects::Group(g) => { - let community_uri = g.inner.object_props.get_id().unwrap().to_string(); + let community_uri = g.inner.id().unwrap().to_string(); let community = get_or_fetch_and_upsert_remote_community(&community_uri, client, pool).await?; @@ -174,15 +164,15 @@ pub async fn search_by_apub_id( response } - SearchAcceptedObjects::Page(p) => { - let post_form = PostForm::from_apub(&p, client, pool).await?; + SearchAcceptedObjects::Page(mut p) => { + let post_form = PostForm::from_apub(&mut p, client, pool).await?; let p = blocking(pool, move |conn| upsert_post(&post_form, conn)).await??; response.posts = vec![blocking(pool, move |conn| PostView::read(conn, p.id, None)).await??]; response } - SearchAcceptedObjects::Comment(c) => { + SearchAcceptedObjects::Comment(mut c) => { let post_url = c .object_props .get_many_in_reply_to_xsd_any_uris() @@ -192,9 +182,9 @@ pub async fn search_by_apub_id( .to_string(); // TODO: also fetch parent comments if any - let post = fetch_remote_object(client, &Url::parse(&post_url)?).await?; - let post_form = PostForm::from_apub(&post, client, pool).await?; - let comment_form = CommentForm::from_apub(&c, client, pool).await?; + let mut post = fetch_remote_object(client, &Url::parse(&post_url)?).await?; + let post_form = PostForm::from_apub(&mut post, client, pool).await?; + let comment_form = CommentForm::from_apub(&mut c, client, pool).await?; blocking(pool, move |conn| upsert_post(&post_form, conn)).await??; let c = blocking(pool, move |conn| upsert_comment(&comment_form, conn)).await??; @@ -224,9 +214,9 @@ pub async fn get_or_fetch_and_upsert_remote_user( // If its older than a day, re-fetch it Ok(u) if !u.local && should_refetch_actor(u.last_refreshed_at) => { debug!("Fetching and updating from remote user: {}", apub_id); - let person = fetch_remote_object::<PersonExt>(client, &Url::parse(apub_id)?).await?; + let mut person = fetch_remote_object::<PersonExt>(client, &Url::parse(apub_id)?).await?; - let mut uf = UserForm::from_apub(&person, client, pool).await?; + let mut uf = UserForm::from_apub(&mut person, client, pool).await?; uf.last_refreshed_at = Some(naive_now()); let user = blocking(pool, move |conn| User_::update(conn, u.id, &uf)).await??; @@ -235,9 +225,9 @@ pub async fn get_or_fetch_and_upsert_remote_user( Ok(u) => Ok(u), Err(NotFound {}) => { debug!("Fetching and creating remote user: {}", apub_id); - let person = fetch_remote_object::<PersonExt>(client, &Url::parse(apub_id)?).await?; + let mut person = fetch_remote_object::<PersonExt>(client, &Url::parse(apub_id)?).await?; - let uf = UserForm::from_apub(&person, client, pool).await?; + let uf = UserForm::from_apub(&mut person, client, pool).await?; let user = blocking(pool, move |conn| User_::create(conn, &uf)).await??; Ok(user) @@ -275,9 +265,9 @@ pub async fn get_or_fetch_and_upsert_remote_community( match community { Ok(c) if !c.local && should_refetch_actor(c.last_refreshed_at) => { debug!("Fetching and updating from remote community: {}", apub_id); - let group = fetch_remote_object::<GroupExt>(client, &Url::parse(apub_id)?).await?; + let mut group = fetch_remote_object::<GroupExt>(client, &Url::parse(apub_id)?).await?; - let mut cf = CommunityForm::from_apub(&group, client, pool).await?; + let mut cf = CommunityForm::from_apub(&mut group, client, pool).await?; cf.last_refreshed_at = Some(naive_now()); let community = blocking(pool, move |conn| Community::update(conn, c.id, &cf)).await??; @@ -286,17 +276,19 @@ pub async fn get_or_fetch_and_upsert_remote_community( Ok(c) => Ok(c), Err(NotFound {}) => { debug!("Fetching and creating remote community: {}", apub_id); - let group = fetch_remote_object::<GroupExt>(client, &Url::parse(apub_id)?).await?; + let mut group = fetch_remote_object::<GroupExt>(client, &Url::parse(apub_id)?).await?; - let cf = CommunityForm::from_apub(&group, client, pool).await?; + let cf = CommunityForm::from_apub(&mut group, client, pool).await?; let community = blocking(pool, move |conn| Community::create(conn, &cf)).await??; // Also add the community moderators too - let creator_and_moderator_uris = group - .inner - .object_props - .get_many_attributed_to_xsd_any_uris() - .unwrap(); + let attributed_to = group.inner.take_attributed_to().unwrap(); + let creator_and_moderator_uris: Vec<&XsdAnyUri> = attributed_to + .as_many() + .unwrap() + .iter() + .map(|a| a.as_xsd_any_uri().unwrap()) + .collect(); let mut creator_and_moderators = Vec::new(); @@ -350,8 +342,8 @@ pub async fn get_or_fetch_and_insert_remote_post( Ok(p) => Ok(p), Err(NotFound {}) => { debug!("Fetching and creating remote post: {}", post_ap_id); - let post = fetch_remote_object::<PageExt>(client, &Url::parse(post_ap_id)?).await?; - let post_form = PostForm::from_apub(&post, client, pool).await?; + let mut post = fetch_remote_object::<PageExt>(client, &Url::parse(post_ap_id)?).await?; + let post_form = PostForm::from_apub(&mut post, client, pool).await?; let post = blocking(pool, move |conn| Post::create(conn, &post_form)).await??; @@ -388,8 +380,8 @@ pub async fn get_or_fetch_and_insert_remote_comment( "Fetching and creating remote comment and its parents: {}", comment_ap_id ); - let comment = fetch_remote_object::<Note>(client, &Url::parse(comment_ap_id)?).await?; - let comment_form = CommentForm::from_apub(&comment, client, pool).await?; + let mut comment = fetch_remote_object::<Note>(client, &Url::parse(comment_ap_id)?).await?; + let comment_form = CommentForm::from_apub(&mut comment, client, pool).await?; let comment = blocking(pool, move |conn| Comment::create(conn, &comment_form)).await??; diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs index 90df8734..eeac5fec 100644 --- a/server/src/apub/mod.rs +++ b/server/src/apub/mod.rs @@ -16,41 +16,35 @@ use crate::{ page_extension::PageExtension, signatures::{PublicKey, PublicKeyExtension}, }, - convert_datetime, - db::user::User_, + blocking, request::{retry, RecvError}, routes::webfinger::WebFingerResponse, DbPool, LemmyError, - MentionData, - Settings, }; -use activitystreams::{ - actor::{properties::ApActorProperties, Group, Person}, - object::Page, +use activitystreams::object::Page; +use activitystreams_ext::{Ext1, Ext2}; +use activitystreams_new::{ + activity::Follow, + actor::{ApActor, Group, Person}, + object::Tombstone, + prelude::*, }; -use activitystreams_ext::{Ext1, Ext2, Ext3}; -use activitystreams_new::{activity::Follow, object::Tombstone, prelude::*}; use actix_web::{body::Body, client::Client, HttpResponse}; use chrono::NaiveDateTime; +use failure::_core::fmt::Debug; +use lemmy_db::{activity::do_insert_activity, user::User_}; +use lemmy_utils::{convert_datetime, get_apub_protocol_string, settings::Settings, MentionData}; use log::debug; use serde::Serialize; use url::Url; -type GroupExt = Ext3<Group, GroupExtension, ApActorProperties, PublicKeyExtension>; -type PersonExt = Ext2<Person, ApActorProperties, PublicKeyExtension>; +type GroupExt = Ext2<ApActor<Group>, GroupExtension, PublicKeyExtension>; +type PersonExt = Ext1<ApActor<Person>, PublicKeyExtension>; type PageExt = Ext1<Page, PageExtension>; pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json"; -pub enum EndpointType { - Community, - User, - Post, - Comment, - PrivateMessage, -} - /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub /// headers. fn create_apub_response<T>(data: &T) -> HttpResponse<Body> @@ -71,34 +65,6 @@ where .json(data) } -/// Generates the ActivityPub ID for a given object type and ID. -pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url { - let point = match endpoint_type { - EndpointType::Community => "c", - EndpointType::User => "u", - EndpointType::Post => "post", - EndpointType::Comment => "comment", - EndpointType::PrivateMessage => "private_message", - }; - - Url::parse(&format!( - "{}://{}/{}/{}", - get_apub_protocol_string(), - Settings::get().hostname, - point, - name - )) - .unwrap() -} - -pub fn get_apub_protocol_string() -> &'static str { - if Settings::get().federation.tls_enabled { - "https" - } else { - "http" - } -} - // Checks if the ID has a valid format, correct scheme, and is in the allowed instance list. fn is_apub_id_valid(apub_id: &Url) -> bool { debug!("Checking {}", apub_id); @@ -163,7 +129,7 @@ fn create_tombstone( pub trait FromApub { type ApubType; async fn from_apub( - apub: &Self::ApubType, + apub: &mut Self::ApubType, client: &Client, pool: &DbPool, ) -> Result<Self, LemmyError> @@ -372,3 +338,19 @@ pub async fn fetch_webfinger_url( .to_owned() .ok_or_else(|| format_err!("No href found.").into()) } + +pub async fn insert_activity<T>( + user_id: i32, + data: T, + local: bool, + pool: &DbPool, +) -> Result<(), LemmyError> +where + T: Serialize + Debug + Send + 'static, +{ + blocking(pool, move |conn| { + do_insert_activity(conn, user_id, &data, local) + }) + .await??; + Ok(()) +} diff --git a/server/src/apub/post.rs b/server/src/apub/post.rs index 60cb0b55..ba0372c4 100644 --- a/server/src/apub/post.rs +++ b/server/src/apub/post.rs @@ -6,7 +6,6 @@ use crate::{ create_tombstone, extensions::page_extension::PageExtension, fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user}, - get_apub_protocol_string, ActorType, ApubLikeableType, ApubObjectType, @@ -15,17 +14,9 @@ use crate::{ ToApub, }, blocking, - convert_datetime, - db::{ - community::Community, - post::{Post, PostForm}, - user::User_, - Crud, - }, routes::DbPoolParam, DbPool, LemmyError, - Settings, }; use activitystreams::{ activity::{Create, Delete, Dislike, Like, Remove, Undo, Update}, @@ -36,6 +27,13 @@ use activitystreams::{ use activitystreams_ext::Ext1; use activitystreams_new::object::Tombstone; use actix_web::{body::Body, client::Client, web, HttpResponse}; +use lemmy_db::{ + community::Community, + post::{Post, PostForm}, + user::User_, + Crud, +}; +use lemmy_utils::{convert_datetime, get_apub_protocol_string, settings::Settings}; use serde::Deserialize; #[derive(Deserialize)] @@ -164,7 +162,7 @@ impl FromApub for PostForm { /// Parse an ActivityPub page received from another instance into a Lemmy post. async fn from_apub( - page: &PageExt, + page: &mut PageExt, client: &Client, pool: &DbPool, ) -> Result<PostForm, LemmyError> { diff --git a/server/src/apub/private_message.rs b/server/src/apub/private_message.rs index ae4c3626..567a6178 100644 --- a/server/src/apub/private_message.rs +++ b/server/src/apub/private_message.rs @@ -3,18 +3,12 @@ use crate::{ activities::send_activity, create_tombstone, fetcher::get_or_fetch_and_upsert_remote_user, + insert_activity, ApubObjectType, FromApub, ToApub, }, blocking, - convert_datetime, - db::{ - activity::insert_activity, - private_message::{PrivateMessage, PrivateMessageForm}, - user::User_, - Crud, - }, DbPool, LemmyError, }; @@ -25,6 +19,12 @@ use activitystreams::{ }; use activitystreams_new::object::Tombstone; use actix_web::client::Client; +use lemmy_db::{ + private_message::{PrivateMessage, PrivateMessageForm}, + user::User_, + Crud, +}; +use lemmy_utils::convert_datetime; #[async_trait::async_trait(?Send)] impl ToApub for PrivateMessage { @@ -71,7 +71,7 @@ impl FromApub for PrivateMessageForm { /// Parse an ActivityPub note received from another instance into a Lemmy Private message async fn from_apub( - note: &Note, + note: &mut Note, client: &Client, pool: &DbPool, ) -> Result<PrivateMessageForm, LemmyError> { diff --git a/server/src/apub/shared_inbox.rs b/server/src/apub/shared_inbox.rs index 66773252..75ce3415 100644 --- a/server/src/apub/shared_inbox.rs +++ b/server/src/apub/shared_inbox.rs @@ -5,6 +5,7 @@ use crate::{ post::PostResponse, }, apub::{ + community::do_announce, extensions::signatures::verify, fetcher::{ get_or_fetch_and_insert_remote_comment, @@ -12,25 +13,13 @@ use crate::{ get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user, }, + insert_activity, FromApub, GroupExt, PageExt, }, blocking, - db::{ - activity::insert_activity, - comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, - comment_view::CommentView, - community::{Community, CommunityForm}, - community_view::CommunityView, - post::{Post, PostForm, PostLike, PostLikeForm}, - post_view::PostView, - Crud, - Likeable, - }, - naive_now, routes::{ChatServerParam, DbPoolParam}, - scrape_text_for_mentions, websocket::{ server::{Sen |