Remove usage of Option::unwrap() in activitypub code #80

Merged
dessalines merged 2 commits from apub-remove-unwrap into main 2020-08-11 14:31:09 +00:00
22 changed files with 528 additions and 282 deletions

View File

@ -31,6 +31,18 @@ use regex::{Regex, RegexBuilder};
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use url::Url; use url::Url;
#[macro_export]
macro_rules! location_info {
() => {
format!(
"None value at {}:{}, column {}",
file!(),
line!(),
column!()
)
};
}
pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> { pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> {
DateTime::<Utc>::from_utc(ndt, Utc) DateTime::<Utc>::from_utc(ndt, Utc)
} }

View File

@ -605,11 +605,11 @@ impl Perform for Oper<FollowCommunity> {
// Dont actually add to the community followers here, because you need // Dont actually add to the community followers here, because you need
// to wait for the accept // to wait for the accept
user user
.send_follow(&community.actor_id, &self.client, pool) .send_follow(&community.actor_id()?, &self.client, pool)
.await?; .await?;
} else { } else {
user user
.send_unfollow(&community.actor_id, &self.client, pool) .send_unfollow(&community.actor_id()?, &self.client, pool)
.await?; .await?;
let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
if blocking(pool, unfollow).await?.is_err() { if blocking(pool, unfollow).await?.is_err() {

View File

@ -21,7 +21,7 @@ use uuid::Uuid;
pub async fn send_activity_to_community( pub async fn send_activity_to_community(
creator: &User_, creator: &User_,
community: &Community, community: &Community,
to: Vec<String>, to: Vec<Url>,
activity: AnyBase, activity: AnyBase,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
@ -43,17 +43,18 @@ pub async fn send_activity(
client: &Client, client: &Client,
activity: &AnyBase, activity: &AnyBase,
actor: &dyn ActorType, actor: &dyn ActorType,
to: Vec<String>, to: Vec<Url>,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let activity = serde_json::to_string(&activity)?; let activity = serde_json::to_string(&activity)?;
debug!("Sending activitypub activity {} to {:?}", activity, to); debug!("Sending activitypub activity {} to {:?}", activity, to);
for t in to { for to_url in to {
let to_url = Url::parse(&t)?;
check_is_apub_id_valid(&to_url)?; check_is_apub_id_valid(&to_url)?;
let res = retry_custom(|| async { let res = retry_custom(|| async {
let request = client.post(&t).header("Content-Type", "application/json"); let request = client
.post(to_url.as_str())
.header("Content-Type", "application/json");
match sign(request, actor, activity.clone()).await { match sign(request, actor, activity.clone()).await {
Ok(signed) => Ok(signed.send().await), Ok(signed) => Ok(signed.send().await),

View File

@ -41,6 +41,7 @@ use activitystreams::{
public, public,
}; };
use actix_web::{body::Body, client::Client, web::Path, HttpResponse}; use actix_web::{body::Body, client::Client, web::Path, HttpResponse};
use anyhow::Context;
use itertools::Itertools; use itertools::Itertools;
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm}, comment::{Comment, CommentForm},
@ -49,7 +50,13 @@ use lemmy_db::{
user::User_, user::User_,
Crud, Crud,
}; };
use lemmy_utils::{convert_datetime, remove_slurs, scrape_text_for_mentions, MentionData}; use lemmy_utils::{
convert_datetime,
location_info,
remove_slurs,
scrape_text_for_mentions,
MentionData,
};
use log::debug; use log::debug;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Error; use serde_json::Error;
@ -136,21 +143,21 @@ impl FromApub for CommentForm {
) -> Result<CommentForm, LemmyError> { ) -> Result<CommentForm, LemmyError> {
let creator_actor_id = &note let creator_actor_id = &note
.attributed_to() .attributed_to()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.unwrap(); .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?; let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
let mut in_reply_tos = note let mut in_reply_tos = note
.in_reply_to() .in_reply_to()
.as_ref() .as_ref()
.unwrap() .context(location_info!())?
.as_many() .as_many()
.unwrap() .context(location_info!())?
.iter() .iter()
.map(|i| i.as_xsd_any_uri().unwrap()); .map(|i| i.as_xsd_any_uri().context(""));
let post_ap_id = in_reply_tos.next().unwrap(); let post_ap_id = in_reply_tos.next().context(location_info!())??;
// This post, or the parent comment might not yet exist on this server yet, fetch them. // This post, or the parent comment might not yet exist on this server yet, fetch them.
let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?; let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
@ -159,7 +166,7 @@ impl FromApub for CommentForm {
// For deeply nested comments, FromApub automatically gets called recursively // For deeply nested comments, FromApub automatically gets called recursively
let parent_id: Option<i32> = match in_reply_tos.next() { let parent_id: Option<i32> = match in_reply_tos.next() {
Some(parent_comment_uri) => { Some(parent_comment_uri) => {
let parent_comment_ap_id = &parent_comment_uri; let parent_comment_ap_id = &parent_comment_uri?;
let parent_comment = let parent_comment =
get_or_fetch_and_insert_comment(&parent_comment_ap_id, client, pool).await?; get_or_fetch_and_insert_comment(&parent_comment_ap_id, client, pool).await?;
@ -169,9 +176,9 @@ impl FromApub for CommentForm {
}; };
let content = note let content = note
.content() .content()
.unwrap() .context(location_info!())?
.as_single_xsd_string() .as_single_xsd_string()
.unwrap() .context(location_info!())?
.to_string(); .to_string();
let content_slurs_removed = remove_slurs(&content); let content_slurs_removed = remove_slurs(&content);
@ -295,7 +302,7 @@ impl ApubObjectType for Comment {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
delete.into_any_base()?, delete.into_any_base()?,
client, client,
pool, pool,
@ -337,7 +344,7 @@ impl ApubObjectType for Comment {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,
@ -370,7 +377,7 @@ impl ApubObjectType for Comment {
send_activity_to_community( send_activity_to_community(
&mod_, &mod_,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
remove.into_any_base()?, remove.into_any_base()?,
client, client,
pool, pool,
@ -412,7 +419,7 @@ impl ApubObjectType for Comment {
send_activity_to_community( send_activity_to_community(
&mod_, &mod_,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,
@ -448,7 +455,7 @@ impl ApubLikeableType for Comment {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
like.into_any_base()?, like.into_any_base()?,
client, client,
pool, pool,
@ -481,7 +488,7 @@ impl ApubLikeableType for Comment {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
dislike.into_any_base()?, dislike.into_any_base()?,
client, client,
pool, pool,
@ -522,7 +529,7 @@ impl ApubLikeableType for Comment {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,
@ -534,7 +541,7 @@ impl ApubLikeableType for Comment {
struct MentionsAndAddresses { struct MentionsAndAddresses {
addressed_ccs: Vec<String>, addressed_ccs: Vec<String>,
inboxes: Vec<String>, inboxes: Vec<Url>,
tags: Vec<Mention>, tags: Vec<Mention>,
} }
@ -569,7 +576,7 @@ async fn collect_non_local_mentions_and_addresses(
.filter(|m| !m.is_local()) .filter(|m| !m.is_local())
.collect::<Vec<MentionData>>(); .collect::<Vec<MentionData>>();
let mut mention_inboxes = Vec::new(); let mut mention_inboxes: Vec<Url> = Vec::new();
for mention in &mentions { for mention in &mentions {
// TODO should it be fetching it every time? // TODO should it be fetching it every time?
if let Ok(actor_id) = fetch_webfinger_url(mention, client).await { if let Ok(actor_id) = fetch_webfinger_url(mention, client).await {
@ -577,7 +584,7 @@ async fn collect_non_local_mentions_and_addresses(
addressed_ccs.push(actor_id.to_owned().to_string()); addressed_ccs.push(actor_id.to_owned().to_string());
let mention_user = get_or_fetch_and_upsert_user(&actor_id, client, pool).await?; let mention_user = get_or_fetch_and_upsert_user(&actor_id, client, pool).await?;
let shared_inbox = mention_user.get_shared_inbox_url(); let shared_inbox = mention_user.get_shared_inbox_url()?;
mention_inboxes.push(shared_inbox); mention_inboxes.push(shared_inbox);
let mut mention_tag = Mention::new(); let mut mention_tag = Mention::new();
@ -586,7 +593,7 @@ async fn collect_non_local_mentions_and_addresses(
} }
} }
let mut inboxes = vec![community.get_shared_inbox_url()]; let mut inboxes = vec![community.get_shared_inbox_url()?];
inboxes.extend(mention_inboxes); inboxes.extend(mention_inboxes);
inboxes = inboxes.into_iter().unique().collect(); inboxes = inboxes.into_iter().unique().collect();

View File

@ -7,8 +7,7 @@ use crate::{
create_apub_tombstone_response, create_apub_tombstone_response,
create_tombstone, create_tombstone,
extensions::group_extensions::GroupExtension, extensions::group_extensions::GroupExtension,
fetcher::get_or_fetch_and_upsert_user, fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_user},
get_shared_inbox,
insert_activity, insert_activity,
ActorType, ActorType,
FromApub, FromApub,
@ -40,6 +39,7 @@ use activitystreams::{
}; };
use activitystreams_ext::Ext2; use activitystreams_ext::Ext2;
use actix_web::{body::Body, client::Client, web, HttpResponse}; use actix_web::{body::Body, client::Client, web, HttpResponse};
use anyhow::Context;
use itertools::Itertools; use itertools::Itertools;
use lemmy_db::{ use lemmy_db::{
community::{Community, CommunityForm}, community::{Community, CommunityForm},
@ -48,7 +48,7 @@ use lemmy_db::{
post::Post, post::Post,
user::User_, user::User_,
}; };
use lemmy_utils::convert_datetime; use lemmy_utils::{convert_datetime, get_apub_protocol_string, location_info};
use serde::Deserialize; use serde::Deserialize;
use url::Url; use url::Url;
@ -99,7 +99,7 @@ impl ToApub for Community {
.set_following(self.get_following_url().parse()?) .set_following(self.get_following_url().parse()?)
.set_liked(self.get_liked_url().parse()?) .set_liked(self.get_liked_url().parse()?)
.set_endpoints(Endpoints { .set_endpoints(Endpoints {
shared_inbox: Some(self.get_shared_inbox_url().parse()?), shared_inbox: Some(self.get_shared_inbox_url()?),
..Default::default() ..Default::default()
}); });
@ -113,7 +113,7 @@ impl ToApub for Community {
Ok(Ext2::new( Ok(Ext2::new(
ap_actor, ap_actor,
group_extension, group_extension,
self.get_public_key_ext(), self.get_public_key_ext()?,
)) ))
} }
@ -128,11 +128,11 @@ impl ActorType for Community {
self.actor_id.to_owned() self.actor_id.to_owned()
} }
fn public_key(&self) -> String { fn public_key(&self) -> Option<String> {
self.public_key.to_owned().unwrap() self.public_key.to_owned()
} }
fn private_key(&self) -> String { fn private_key(&self) -> Option<String> {
self.private_key.to_owned().unwrap() self.private_key.to_owned()
} }
/// As a local community, accept the follow request from a remote user. /// As a local community, accept the follow request from a remote user.
@ -142,10 +142,14 @@ impl ActorType for Community {
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let actor_uri = follow.actor()?.as_single_xsd_any_uri().unwrap().to_string(); let actor_uri = follow
.actor()?
.as_single_xsd_any_uri()
.context(location_info!())?;
let actor = get_or_fetch_and_upsert_actor(actor_uri, client, pool).await?;
let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?); let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
let to = format!("{}/inbox", actor_uri); let to = actor.get_inbox_url()?;
accept accept
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(AcceptType::Accept)?) .set_id(generate_activity_id(AcceptType::Accept)?)
@ -279,7 +283,10 @@ impl ActorType for Community {
} }
/// For a given community, returns the inboxes of all followers. /// For a given community, returns the inboxes of all followers.
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<String>, LemmyError> { ///
/// TODO: this function is very badly implemented, we should just store shared_inbox_url in
/// CommunityFollowerView
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
let id = self.id; let id = self.id;
let inboxes = blocking(pool, move |conn| { let inboxes = blocking(pool, move |conn| {
@ -288,8 +295,22 @@ impl ActorType for Community {
.await??; .await??;
let inboxes = inboxes let inboxes = inboxes
.into_iter() .into_iter()
.map(|c| get_shared_inbox(&Url::parse(&c.user_actor_id).unwrap())) .map(|u| -> Result<Url, LemmyError> {
.filter(|s| !s.is_empty()) let url = Url::parse(&u.user_actor_id)?;
let domain = url.domain().context(location_info!())?;
let port = if let Some(port) = url.port() {
format!(":{}", port)
} else {
"".to_string()
};
Ok(Url::parse(&format!(
"{}://{}{}/inbox",
get_apub_protocol_string(),
domain,
port,
))?)
})
.filter_map(Result::ok)
.unique() .unique()
.collect(); .collect();
@ -298,7 +319,7 @@ impl ActorType for Community {
async fn send_follow( async fn send_follow(
&self, &self,
_follow_actor_id: &str, _follow_actor_id: &Url,
_client: &Client, _client: &Client,
_pool: &DbPool, _pool: &DbPool,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
@ -307,7 +328,7 @@ impl ActorType for Community {
async fn send_unfollow( async fn send_unfollow(
&self, &self,
_follow_actor_id: &str, _follow_actor_id: &Url,
_client: &Client, _client: &Client,
_pool: &DbPool, _pool: &DbPool,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
@ -330,44 +351,50 @@ impl FromApub for CommunityForm {
pool: &DbPool, pool: &DbPool,
expected_domain: Option<Url>, expected_domain: Option<Url>,
) -> Result<Self, LemmyError> { ) -> Result<Self, LemmyError> {
let creator_and_moderator_uris = group.inner.attributed_to().unwrap(); let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?;
let creator_uri = creator_and_moderator_uris let creator_uri = creator_and_moderator_uris
.as_many() .as_many()
.unwrap() .context(location_info!())?
.iter() .iter()
.next() .next()
.unwrap() .context(location_info!())?
.as_xsd_any_uri() .as_xsd_any_uri()
.unwrap(); .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_uri, client, pool).await?; let creator = get_or_fetch_and_upsert_user(creator_uri, client, pool).await?;
let name = group let name = group
.inner .inner
.name() .name()
.unwrap() .context(location_info!())?
.as_one() .as_one()
.unwrap() .context(location_info!())?
.as_xsd_string() .as_xsd_string()
.unwrap() .context(location_info!())?
.to_string();
let title = group
.inner
.preferred_username()
.context(location_info!())?
.to_string(); .to_string();
let title = group.inner.preferred_username().unwrap().to_string();
// TODO: should be parsed as html and tags like <script> removed (or use markdown source) // TODO: should be parsed as html and tags like <script> removed (or use markdown source)
// -> same for post.content etc // -> same for post.content etc
let description = group let description = group
.inner .inner
.content() .content()
.map(|s| s.as_single_xsd_string().unwrap().into()); .map(|s| s.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
check_slurs(&name)?; check_slurs(&name)?;
check_slurs(&title)?; check_slurs(&title)?;
check_slurs_opt(&description)?; check_slurs_opt(&description)?;
let icon = match group.icon() { let icon = match group.icon() {
Some(any_image) => Some( Some(any_image) => Some(
Image::from_any_base(any_image.as_one().unwrap().clone()) Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
.unwrap() .context(location_info!())?
.unwrap() .context(location_info!())?
.url() .url()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.map(|u| u.to_string()), .map(|u| u.to_string()),
), ),
@ -376,11 +403,11 @@ impl FromApub for CommunityForm {
let banner = match group.image() { let banner = match group.image() {
Some(any_image) => Some( Some(any_image) => Some(
Image::from_any_base(any_image.as_one().unwrap().clone()) Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
.unwrap() .context(location_info!())?
.unwrap() .context(location_info!())?
.url() .url()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.map(|u| u.to_string()), .map(|u| u.to_string()),
), ),
@ -499,13 +526,15 @@ pub async fn do_announce(
insert_activity(community.creator_id, announce.clone(), true, pool).await?; insert_activity(community.creator_id, announce.clone(), true, pool).await?;
let mut to = community.get_follower_inboxes(pool).await?; let mut to: Vec<Url> = community.get_follower_inboxes(pool).await?;
// dont send to the local instance, nor to the instance where the activity originally came from, // dont send to the local instance, nor to the instance where the activity originally came from,
// because that would result in a database error (same data inserted twice) // because that would result in a database error (same data inserted twice)
// this seems to be the "easiest" stable alternative for remove_item() // this seems to be the "easiest" stable alternative for remove_item()
to.retain(|x| *x != sender.get_shared_inbox_url()); let sender_shared_inbox = sender.get_shared_inbox_url()?;
to.retain(|x| *x != community.get_shared_inbox_url()); to.retain(|x| x != &sender_shared_inbox);
let community_shared_inbox = community.get_shared_inbox_url()?;
to.retain(|x| x != &community_shared_inbox);
send_activity(client, &announce.into_any_base()?, community, to).await?; send_activity(client, &announce.into_any_base()?, community, to).await?;

View File

@ -2,11 +2,12 @@ use crate::{apub::ActorType, LemmyError};
use activitystreams::unparsed::UnparsedMutExt; use activitystreams::unparsed::UnparsedMutExt;
use activitystreams_ext::UnparsedExtension; use activitystreams_ext::UnparsedExtension;
use actix_web::{client::ClientRequest, HttpRequest}; use actix_web::{client::ClientRequest, HttpRequest};
use anyhow::anyhow; use anyhow::{anyhow, Context};
use http_signature_normalization_actix::{ use http_signature_normalization_actix::{
digest::{DigestClient, SignExt}, digest::{DigestClient, SignExt},
Config, Config,
}; };
use lemmy_utils::location_info;
use log::debug; use log::debug;
use openssl::{ use openssl::{
hash::MessageDigest, hash::MessageDigest,
@ -27,7 +28,7 @@ pub async fn sign(
activity: String, activity: String,
) -> Result<DigestClient<String>, LemmyError> { ) -> Result<DigestClient<String>, LemmyError> {
let signing_key_id = format!("{}#main-key", actor.actor_id()?); let signing_key_id = format!("{}#main-key", actor.actor_id()?);
let private_key = actor.private_key(); let private_key = actor.private_key().context(location_info!())?;
let digest_client = request let digest_client = request
.signature_with_digest( .signature_with_digest(
@ -37,8 +38,8 @@ pub async fn sign(
activity, activity,
move |signing_string| { move |signing_string| {
let private_key = PKey::private_key_from_pem(private_key.as_bytes())?; let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &private_key)?;
signer.update(signing_string.as_bytes()).unwrap(); signer.update(signing_string.as_bytes())?;
Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, LemmyError> Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, LemmyError>
}, },
@ -49,6 +50,7 @@ pub async fn sign(
} }
pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> { pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
let public_key = actor.public_key().context(location_info!())?;
let verified = HTTP_SIG_CONFIG let verified = HTTP_SIG_CONFIG
.begin_verify( .begin_verify(
request.method(), request.method(),
@ -58,12 +60,11 @@ pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyE
.verify(|signature, signing_string| -> Result<bool, LemmyError> { .verify(|signature, signing_string| -> Result<bool, LemmyError> {
debug!( debug!(
"Verifying with key {}, message {}", "Verifying with key {}, message {}",
&actor.public_key(), &public_key, &signing_string
&signing_string
); );
let public_key = PKey::public_key_from_pem(actor.public_key().as_bytes())?; let public_key = PKey::public_key_from_pem(public_key.as_bytes())?;
let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key)?;
verifier.update(&signing_string.as_bytes()).unwrap(); verifier.update(&signing_string.as_bytes())?;
Ok(verifier.verify(&base64::decode(signature)?)?) Ok(verifier.verify(&base64::decode(signature)?)?)
})?; })?;

View File

@ -17,7 +17,7 @@ use crate::{
}; };
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*}; use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
use actix_web::client::Client; use actix_web::client::Client;
use anyhow::anyhow; use anyhow::{anyhow, Context};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{result::Error::NotFound, PgConnection}; use diesel::{result::Error::NotFound, PgConnection};
use lemmy_db::{ use lemmy_db::{
@ -34,7 +34,7 @@ use lemmy_db::{
Joinable, Joinable,
SearchType, SearchType,
}; };
use lemmy_utils::get_apub_protocol_string; use lemmy_utils::{get_apub_protocol_string, location_info};
use log::debug; use log::debug;
use serde::Deserialize; use serde::Deserialize;
use std::{fmt::Debug, time::Duration}; use std::{fmt::Debug, time::Duration};
@ -144,10 +144,10 @@ pub async fn search_by_apub_id(
users: vec![], users: vec![],
}; };
let domain = query_url.domain().unwrap(); let domain = query_url.domain().context("url has no domain")?;
let response = match fetch_remote_object::<SearchAcceptedObjects>(client, &query_url).await? { let response = match fetch_remote_object::<SearchAcceptedObjects>(client, &query_url).await? {
SearchAcceptedObjects::Person(p) => { SearchAcceptedObjects::Person(p) => {
let user_uri = p.inner.id(domain)?.unwrap(); let user_uri = p.inner.id(domain)?.context("person has no id")?;
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?; let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
@ -157,7 +157,7 @@ pub async fn search_by_apub_id(
response response
} }
SearchAcceptedObjects::Group(g) => { SearchAcceptedObjects::Group(g) => {
let community_uri = g.inner.id(domain)?.unwrap(); let community_uri = g.inner.id(domain)?.context("group has no id")?;
let community = get_or_fetch_and_upsert_community(community_uri, client, pool).await?; let community = get_or_fetch_and_upsert_community(community_uri, client, pool).await?;
@ -181,10 +181,19 @@ pub async fn search_by_apub_id(
response response
} }
SearchAcceptedObjects::Comment(c) => { SearchAcceptedObjects::Comment(c) => {
let post_url = c.in_reply_to().as_ref().unwrap().as_many().unwrap(); let post_url = c
.in_reply_to()
.as_ref()
.context(location_info!())?
.as_many()
.context(location_info!())?;
// TODO: also fetch parent comments if any // TODO: also fetch parent comments if any
let x = post_url.first().unwrap().as_xsd_any_uri().unwrap(); let x = post_url
.first()
.context(location_info!())?
.as_xsd_any_uri()
.context(location_info!())?;
let post = fetch_remote_object(client, x).await?; let post = fetch_remote_object(client, x).await?;
let post_form = PostForm::from_apub(&post, client, pool, Some(query_url.clone())).await?; let post_form = PostForm::from_apub(&post, client, pool, Some(query_url.clone())).await?;
let comment_form = CommentForm::from_apub(&c, client, pool, Some(query_url)).await?; let comment_form = CommentForm::from_apub(&c, client, pool, Some(query_url)).await?;
@ -312,13 +321,13 @@ async fn fetch_remote_community(
.await??; .await??;
// Also add the community moderators too // Also add the community moderators too
let attributed_to = group.inner.attributed_to().unwrap(); let attributed_to = group.inner.attributed_to().context(location_info!())?;
let creator_and_moderator_uris: Vec<&Url> = attributed_to let creator_and_moderator_uris: Vec<&Url> = attributed_to
.as_many() .as_many()
.unwrap() .context(location_info!())?
.iter() .iter()
.map(|a| a.as_xsd_any_uri().unwrap()) .map(|a| a.as_xsd_any_uri().context(""))
.collect(); .collect::<Result<Vec<&Url>, anyhow::Error>>()?;
let mut creator_and_moderators = Vec::new(); let mut creator_and_moderators = Vec::new();
@ -348,9 +357,9 @@ async fn fetch_remote_community(
// fetch outbox (maybe make this conditional) // fetch outbox (maybe make this conditional)
let outbox = let outbox =
fetch_remote_object::<OrderedCollection>(client, &community.get_outbox_url()?).await?; fetch_remote_object::<OrderedCollection>(client, &community.get_outbox_url()?).await?;
let outbox_items = outbox.items().unwrap().clone(); let outbox_items = outbox.items().context(location_info!())?.clone();
for o in outbox_items.many().unwrap() { for o in outbox_items.many().context(location_info!())? {
let page = PageExt::from_any_base(o)?.unwrap(); let page = PageExt::from_any_base(o)?.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, None).await?; let post = PostForm::from_apub(&page, client, pool, None).await?;
let post_ap_id = post.ap_id.clone(); let post_ap_id = post.ap_id.clone();
// Check whether the post already exists in the local db // Check whether the post already exists in the local db
@ -452,7 +461,7 @@ pub async fn get_or_fetch_and_insert_comment(
// Ok( // Ok(
// items // items
// .unwrap() // .context(location_info!())?
// .map(|obox: &BaseBox| -> Result<PostForm, LemmyError> { // .map(|obox: &BaseBox| -> Result<PostForm, LemmyError> {
// let page = obox.clone().to_concrete::<Page>()?; // let page = obox.clone().to_concrete::<Page>()?;
// PostForm::from_page(&page, conn) // PostForm::from_page(&page, conn)

View File

@ -21,6 +21,8 @@ use activitystreams::{
prelude::ExtendsExt, prelude::ExtendsExt,
}; };
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_utils::location_info;
pub async fn receive_announce( pub async fn receive_announce(
activity: AnyBase, activity: AnyBase,
@ -28,15 +30,15 @@ pub async fn receive_announce(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let announce = Announce::from_any_base(activity)?.unwrap(); let announce = Announce::from_any_base(activity)?.context(location_info!())?;
// ensure that announce and community come from the same instance // ensure that announce and community come from the same instance
let community = get_community_id_from_activity(&announce)?; let community = get_community_id_from_activity(&announce)?;
announce.id(community.domain().unwrap())?; announce.id(community.domain().context(location_info!())?)?;
let kind = announce.object().as_single_kind_str(); let kind = announce.object().as_single_kind_str();
let object = announce.object(); let object = announce.object();
let object2 = object.clone().one().unwrap(); let object2 = object.clone().one().context(location_info!())?;
match kind { match kind {
Some("Create") => receive_create(object2, client, pool, chat_server).await, Some("Create") => receive_create(object2, client, pool, chat_server).await,
Some("Update") => receive_update(object2, client, pool, chat_server).await, Some("Update") => receive_update(object2, client, pool, chat_server).await,

View File

@ -24,6 +24,7 @@ use crate::{
}; };
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm}, comment::{Comment, CommentForm},
comment_view::CommentView, comment_view::CommentView,
@ -31,7 +32,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Crud, Crud,
}; };
use lemmy_utils::scrape_text_for_mentions; use lemmy_utils::{location_info, scrape_text_for_mentions};
pub async fn receive_create( pub async fn receive_create(
activity: AnyBase, activity: AnyBase,
@ -39,11 +40,11 @@ pub async fn receive_create(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let create = Create::from_any_base(activity)?.unwrap(); let create = Create::from_any_base(activity)?.context(location_info!())?;
// ensure that create and actor come from the same instance // ensure that create and actor come from the same instance
let user = get_user_from_activity(&create, client, pool).await?; let user = get_user_from_activity(&create, client, pool).await?;
create.id(user.actor_id()?.domain().unwrap())?; create.id(user.actor_id()?.domain().context(location_info!())?)?;
match create.object().as_single_kind_str() { match create.object().as_single_kind_str() {
Some("Page") => receive_create_post(create, client, pool, chat_server).await, Some("Page") => receive_create_post(create, client, pool, chat_server).await,
@ -59,7 +60,8 @@ async fn receive_create_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&create, client, pool).await?; let user = get_user_from_activity(&create, client, pool).await?;
let page = PageExt::from_any_base(create.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?; let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
@ -91,7 +93,8 @@ async fn receive_create_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&create, client, pool).await?; let user = get_user_from_activity(&create, client, pool).await?;
let note = Note::from_any_base(create.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(create.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)).await?; let comment = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)).await?;

View File

@ -23,6 +23,7 @@ use crate::{
}; };
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm}, comment::{Comment, CommentForm},
comment_view::CommentView, comment_view::CommentView,
@ -33,6 +34,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Crud, Crud,
}; };
use lemmy_utils::location_info;
pub async fn receive_delete( pub async fn receive_delete(
activity: AnyBase, activity: AnyBase,
@ -40,7 +42,7 @@ pub async fn receive_delete(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let delete = Delete::from_any_base(activity)?.unwrap(); let delete = Delete::from_any_base(activity)?.context(location_info!())?;
match delete.object().as_single_kind_str() { match delete.object().as_single_kind_str() {
Some("Page") => receive_delete_post(delete, client, pool, chat_server).await, Some("Page") => receive_delete_post(delete, client, pool, chat_server).await,
Some("Note") => receive_delete_comment(delete, client, pool, chat_server).await, Some("Note") => receive_delete_comment(delete, client, pool, chat_server).await,
@ -56,7 +58,8 @@ async fn receive_delete_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&delete, client, pool).await?; let user = get_user_from_activity(&delete, client, pool).await?;
let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)) let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
.await? .await?
@ -110,7 +113,8 @@ async fn receive_delete_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&delete, client, pool).await?; let user = get_user_from_activity(&delete, client, pool).await?;
let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment_ap_id = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)) let comment_ap_id = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?))
.await? .await?
@ -166,7 +170,8 @@ async fn receive_delete_community(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let group = GroupExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let user = get_user_from_activity(&delete, client, pool).await?; let user = get_user_from_activity(&delete, client, pool).await?;
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?)) let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))

View File

@ -21,6 +21,7 @@ use crate::{
}; };
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
comment::{CommentForm, CommentLike, CommentLikeForm}, comment::{CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView, comment_view::CommentView,
@ -28,6 +29,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Likeable, Likeable,
}; };
use lemmy_utils::location_info;
pub async fn receive_dislike( pub async fn receive_dislike(
activity: AnyBase, activity: AnyBase,
@ -35,7 +37,7 @@ pub async fn receive_dislike(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let dislike = Dislike::from_any_base(activity)?.unwrap(); let dislike = Dislike::from_any_base(activity)?.context(location_info!())?;
match dislike.object().as_single_kind_str() { match dislike.object().as_single_kind_str() {
Some("Page") => receive_dislike_post(dislike, client, pool, chat_server).await, Some("Page") => receive_dislike_post(dislike, client, pool, chat_server).await,
Some("Note") => receive_dislike_comment(dislike, client, pool, chat_server).await, Some("Note") => receive_dislike_comment(dislike, client, pool, chat_server).await,
@ -50,7 +52,14 @@ async fn receive_dislike_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&dislike, client, pool).await?; let user = get_user_from_activity(&dislike, client, pool).await?;
let page = PageExt::from_any_base(dislike.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(
dislike
.object()
.to_owned()
.one()
.context(location_info!())?,
)?
.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, None).await?; let post = PostForm::from_apub(&page, client, pool, None).await?;
@ -90,7 +99,14 @@ async fn receive_dislike_comment(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let note = Note::from_any_base(dislike.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(
dislike
.object()
.to_owned()
.one()
.context(location_info!())?,
)?
.context(location_info!())?;
let user = get_user_from_activity(&dislike, client, pool).await?; let user = get_user_from_activity(&dislike, client, pool).await?;
let comment = CommentForm::from_apub(&note, client, pool, None).await?; let comment = CommentForm::from_apub(&note, client, pool, None).await?;

View File

@ -21,6 +21,7 @@ use crate::{
}; };
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
comment::{CommentForm, CommentLike, CommentLikeForm}, comment::{CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView, comment_view::CommentView,
@ -28,6 +29,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Likeable, Likeable,
}; };
use lemmy_utils::location_info;
pub async fn receive_like( pub async fn receive_like(
activity: AnyBase, activity: AnyBase,
@ -35,7 +37,7 @@ pub async fn receive_like(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let like = Like::from_any_base(activity)?.unwrap(); let like = Like::from_any_base(activity)?.context(location_info!())?;
match like.object().as_single_kind_str() { match like.object().as_single_kind_str() {
Some("Page") => receive_like_post(like, client, pool, chat_server).await, Some("Page") => receive_like_post(like, client, pool, chat_server).await,
Some("Note") => receive_like_comment(like, client, pool, chat_server).await, Some("Note") => receive_like_comment(like, client, pool, chat_server).await,
@ -50,7 +52,8 @@ async fn receive_like_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&like, client, pool).await?; let user = get_user_from_activity(&like, client, pool).await?;
let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, None).await?; let post = PostForm::from_apub(&page, client, pool, None).await?;
@ -90,7 +93,8 @@ async fn receive_like_comment(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(like.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let user = get_user_from_activity(&like, client, pool).await?; let user = get_user_from_activity(&like, client, pool).await?;
let comment = CommentForm::from_apub(&note, client, pool, None).await?; let comment = CommentForm::from_apub(&note, client, pool, None).await?;

View File

@ -24,7 +24,7 @@ use crate::{
}; };
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::anyhow; use anyhow::{anyhow, Context};
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm}, comment::{Comment, CommentForm},
comment_view::CommentView, comment_view::CommentView,
@ -35,6 +35,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Crud, Crud,
}; };
use lemmy_utils::location_info;
pub async fn receive_remove( pub async fn receive_remove(
activity: AnyBase, activity: AnyBase,
@ -42,7 +43,7 @@ pub async fn receive_remove(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let remove = Remove::from_any_base(activity)?.unwrap(); let remove = Remove::from_any_base(activity)?.context(location_info!())?;
let actor = get_user_from_activity(&remove, client, pool).await?; let actor = get_user_from_activity(&remove, client, pool).await?;
let community = get_community_id_from_activity(&remove)?; let community = get_community_id_from_activity(&remove)?;
if actor.actor_id()?.domain() != community.domain() { if actor.actor_id()?.domain() != community.domain() {
@ -64,7 +65,8 @@ async fn receive_remove_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(&remove, client, pool).await?; let mod_ = get_user_from_activity(&remove, client, pool).await?;
let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post_ap_id = PostForm::from_apub(&page, client, pool, None) let post_ap_id = PostForm::from_apub(&page, client, pool, None)
.await? .await?
@ -118,7 +120,8 @@ async fn receive_remove_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(&remove, client, pool).await?; let mod_ = get_user_from_activity(&remove, client, pool).await?;
let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment_ap_id = CommentForm::from_apub(&note, client, pool, None) let comment_ap_id = CommentForm::from_apub(&note, client, pool, None)
.await? .await?
@ -175,7 +178,8 @@ async fn receive_remove_community(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(&remove, client, pool).await?; let mod_ = get_user_from_activity(&remove, client, pool).await?;
let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let group = GroupExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?)) let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
.await? .await?

View File

@ -28,7 +28,7 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::anyhow; use anyhow::{anyhow, Context};
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView, comment_view::CommentView,
@ -40,6 +40,7 @@ use lemmy_db::{
Crud, Crud,
Likeable, Likeable,
}; };
use lemmy_utils::location_info;
pub async fn receive_undo( pub async fn receive_undo(
activity: AnyBase, activity: AnyBase,
@ -47,7 +48,7 @@ pub async fn receive_undo(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let undo = Undo::from_any_base(activity)?.unwrap(); let undo = Undo::from_any_base(activity)?.context(location_info!())?;
match undo.object().as_single_kind_str() { match undo.object().as_single_kind_str() {
Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await, Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await, Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
@ -62,10 +63,14 @@ where
T: AsBase<A> + ActorAndObjectRef, T: AsBase<A> + ActorAndObjectRef,
{ {
let outer_actor = outer_activity.actor()?; let outer_actor = outer_activity.actor()?;
let outer_actor_uri = outer_actor.as_single_xsd_any_uri().unwrap(); let outer_actor_uri = outer_actor
.as_single_xsd_any_uri()
.context(location_info!())?;
let inner_actor = inner_activity.actor()?; let inner_actor = inner_activity.actor()?;
let inner_actor_uri = inner_actor.as_single_xsd_any_uri().unwrap(); let inner_actor_uri = inner_actor
.as_single_xsd_any_uri()
.context(location_info!())?;
if outer_actor_uri.domain() != inner_actor_uri.domain() { if outer_actor_uri.domain() != inner_actor_uri.domain() {
Err(anyhow!("Cant undo activities from a different instance").into()) Err(anyhow!("Cant undo activities from a different instance").into())
@ -80,9 +85,13 @@ async fn receive_undo_delete(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let delete = Delete::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap(); let delete = Delete::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
check_is_undo_valid(&undo, &delete)?; check_is_undo_valid(&undo, &delete)?;
let type_ = delete.object().as_single_kind_str().unwrap(); let type_ = delete
.object()
.as_single_kind_str()
.context(location_info!())?;
match type_ { match type_ {
"Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await, "Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
"Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await, "Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
@ -97,10 +106,14 @@ async fn receive_undo_remove(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let remove = Remove::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap(); let remove = Remove::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
check_is_undo_valid(&undo, &remove)?; check_is_undo_valid(&undo, &remove)?;
let type_ = remove.object().as_single_kind_str().unwrap(); let type_ = remove
.object()
.as_single_kind_str()
.context(location_info!())?;
match type_ { match type_ {
"Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await, "Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
"Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await, "Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
@ -115,10 +128,14 @@ async fn receive_undo_like(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let like = Like::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap(); let like = Like::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
check_is_undo_valid(&undo, &like)?; check_is_undo_valid(&undo, &like)?;
let type_ = like.object().as_single_kind_str().unwrap(); let type_ = like
.object()
.as_single_kind_str()
.context(location_info!())?;
match type_ { match type_ {
"Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await, "Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
"Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await, "Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
@ -132,12 +149,16 @@ async fn receive_undo_dislike(
_pool: &DbPool, _pool: &DbPool,
_chat_server: ChatServerParam, _chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let dislike = Dislike::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap(); let dislike = Dislike::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
check_is_undo_valid(&undo, &dislike)?; check_is_undo_valid(&undo, &dislike)?;
// TODO: need to implement Undo<Dislike> // TODO: need to implement Undo<Dislike>
let type_ = dislike.object().as_single_kind_str().unwrap(); let type_ = dislike
.object()
.as_single_kind_str()
.context(location_info!())?;
Err(anyhow!("Undo Delete type {} not supported", type_).into()) Err(anyhow!("Undo Delete type {} not supported", type_).into())
} }
@ -149,7 +170,8 @@ async fn receive_undo_delete_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(delete, client, pool).await?; let user = get_user_from_activity(delete, client, pool).await?;
let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment_ap_id = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)) let comment_ap_id = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?))
.await? .await?
@ -207,7 +229,8 @@ async fn receive_undo_remove_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(remove, client, pool).await?; let mod_ = get_user_from_activity(remove, client, pool).await?;
let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment_ap_id = CommentForm::from_apub(&note, client, pool, None) let comment_ap_id = CommentForm::from_apub(&note, client, pool, None)
.await? .await?
@ -265,7 +288,8 @@ async fn receive_undo_delete_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(delete, client, pool).await?; let user = get_user_from_activity(delete, client, pool).await?;
let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)) let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
.await? .await?
@ -320,7 +344,8 @@ async fn receive_undo_remove_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(remove, client, pool).await?; let mod_ = get_user_from_activity(remove, client, pool).await?;
let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post_ap_id = PostForm::from_apub(&page, client, pool, None) let post_ap_id = PostForm::from_apub(&page, client, pool, None)
.await? .await?
@ -375,7 +400,8 @@ async fn receive_undo_delete_community(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(delete, client, pool).await?; let user = get_user_from_activity(delete, client, pool).await?;
let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap(); let group = GroupExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?)) let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
.await? .await?
@ -441,7 +467,8 @@ async fn receive_undo_remove_community(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let mod_ = get_user_from_activity(remove, client, pool).await?; let mod_ = get_user_from_activity(remove, client, pool).await?;
let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap(); let group = GroupExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?)) let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
.await? .await?
@ -507,7 +534,8 @@ async fn receive_undo_like_comment(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(like, client, pool).await?; let user = get_user_from_activity(like, client, pool).await?;
let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(like.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let comment = CommentForm::from_apub(&note, client, pool, None).await?; let comment = CommentForm::from_apub(&note, client, pool, None).await?;
@ -553,7 +581,8 @@ async fn receive_undo_like_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(like, client, pool).await?; let user = get_user_from_activity(like, client, pool).await?;
let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, None).await?; let post = PostForm::from_apub(&page, client, pool, None).await?;

View File

@ -25,6 +25,7 @@ use crate::{
}; };
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*}; use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse}; use actix_web::{client::Client, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
comment::{Comment, CommentForm}, comment::{Comment, CommentForm},
comment_view::CommentView, comment_view::CommentView,
@ -32,7 +33,7 @@ use lemmy_db::{
post_view::PostView, post_view::PostView,
Crud, Crud,
}; };
use lemmy_utils::scrape_text_for_mentions; use lemmy_utils::{location_info, scrape_text_for_mentions};
pub async fn receive_update( pub async fn receive_update(
activity: AnyBase, activity: AnyBase,
@ -40,11 +41,11 @@ pub async fn receive_update(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let update = Update::from_any_base(activity)?.unwrap(); let update = Update::from_any_base(activity)?.context(location_info!())?;
// ensure that update and actor come from the same instance // ensure that update and actor come from the same instance
let user = get_user_from_activity(&update, client, pool).await?; let user = get_user_from_activity(&update, client, pool).await?;
update.id(user.actor_id()?.domain().unwrap())?; update.id(user.actor_id()?.domain().context(location_info!())?)?;
match update.object().as_single_kind_str() { match update.object().as_single_kind_str() {
Some("Page") => receive_update_post(update, client, pool, chat_server).await, Some("Page") => receive_update_post(update, client, pool, chat_server).await,
@ -60,7 +61,8 @@ async fn receive_update_post(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user = get_user_from_activity(&update, client, pool).await?; let user = get_user_from_activity(&update, client, pool).await?;
let page = PageExt::from_any_base(update.object().to_owned().one().unwrap())?.unwrap(); let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?; let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
@ -97,7 +99,8 @@ async fn receive_update_comment(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let note = Note::from_any_base(update.object().to_owned().one().unwrap())?.unwrap(); let note = Note::from_any_base(update.object().to_owned().one().context(location_info!())?)?
.context(location_info!())?;
let user = get_user_from_activity(&update, client, pool).await?; let user = get_user_from_activity(&update, client, pool).await?;
let comment = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)).await?; let comment = CommentForm::from_apub(&note, client, pool, Some(user.actor_id()?)).await?;

View File

@ -16,12 +16,13 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use actix_web::{client::Client, web, HttpRequest, HttpResponse}; use actix_web::{client::Client, web, HttpRequest, HttpResponse};
use anyhow::anyhow; use anyhow::{anyhow, Context};
use lemmy_db::{ use lemmy_db::{
community::{Community, CommunityFollower, CommunityFollowerForm}, community::{Community, CommunityFollower, CommunityFollowerForm},
user::User_, user::User_,
Followable, Followable,
}; };
use lemmy_utils::location_info;
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
@ -62,7 +63,10 @@ pub async fn community_inbox(
"Community {} received activity {:?}", "Community {} received activity {:?}",
&community.name, &activity &community.name, &activity
); );
let user_uri = activity.actor()?.as_single_xsd_any_uri().unwrap(); let user_uri = activity
.actor()?
.as_single_xsd_any_uri()
.context(location_info!())?;
check_is_apub_id_valid(user_uri)?; check_is_apub_id_valid(user_uri)?;
let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?; let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?;
@ -70,7 +74,7 @@ pub async fn community_inbox(
verify(&request, &user)?; verify(&request, &user)?;
let any_base = activity.clone().into_any_base()?; let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap(); let kind = activity.kind().context(location_info!())?;
let user_id = user.id; let user_id = user.id;
let res = match kind { let res = match kind {
ValidTypes::Follow => handle_follow(any_base, user, community, &client, &db).await, ValidTypes::Follow => handle_follow(any_base, user, community, &client, &db).await,
@ -90,7 +94,7 @@ async fn handle_follow(
client: &Client, client: &Client,
db: &DbPoolParam, db: &DbPoolParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let follow = Follow::from_any_base(activity)?.unwrap(); let follow = Follow::from_any_base(activity)?.context(location_info!())?;
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,
user_id: user.id, user_id: user.id,
@ -113,7 +117,7 @@ async fn handle_undo_follow(
community: Community, community: Community,
db: &DbPoolParam, db: &DbPoolParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let _undo = Undo::from_any_base(activity)?.unwrap(); let _undo = Undo::from_any_base(activity)?.context(location_info!())?;
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,

View File

@ -31,7 +31,9 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use actix_web::{client::Client, web, HttpRequest, HttpResponse}; use actix_web::{client::Client, web, HttpRequest, HttpResponse};
use anyhow::Context;
use lemmy_db::user::User_; use lemmy_db::user::User_;
use lemmy_utils::location_info;
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
@ -67,7 +69,11 @@ pub async fn shared_inbox(
let json = serde_json::to_string(&activity)?; let json = serde_json::to_string(&activity)?;
debug!("Shared inbox received activity: {}", json); debug!("Shared inbox received activity: {}", json);
let sender = &activity.actor()?.to_owned().single_xsd_any_uri().unwrap(); let sender = &activity
.actor()?
.to_owned()
.single_xsd_any_uri()
.context(location_info!())?;
let community = get_community_id_from_activity(&activity)?; let community = get_community_id_from_activity(&activity)?;
check_is_apub_id_valid(sender)?; check_is_apub_id_valid(sender)?;
@ -77,7 +83,7 @@ pub async fn shared_inbox(
verify(&request, actor.as_ref())?; verify(&request, actor.as_ref())?;
let any_base = activity.clone().into_any_base()?; let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap(); let kind = activity.kind().context(location_info!())?;
let res = match kind { let res = match kind {
ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await, ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await, ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
@ -112,7 +118,7 @@ where
T: AsBase<A> + ActorAndObjectRef, T: AsBase<A> + ActorAndObjectRef,
{ {
let actor = activity.actor()?; let actor = activity.actor()?;
let user_uri = actor.as_single_xsd_any_uri().unwrap(); let user_uri = actor.as_single_xsd_any_uri().context(location_info!())?;
get_or_fetch_and_upsert_user(&user_uri, client, pool).await get_or_fetch_and_upsert_user(&user_uri, client, pool).await
} }
@ -122,9 +128,15 @@ pub(in crate::apub::inbox) fn get_community_id_from_activity<T, A>(
where where
T: AsBase<A> + ActorAndObjectRef + AsObject<A>, T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
{ {
let cc = activity.cc().unwrap(); let cc = activity.cc().context(location_info!())?;
let cc = cc.as_many().unwrap(); let cc = cc.as_many().context(location_info!())?;
Ok(cc.first().unwrap().as_xsd_any_uri().unwrap().to_owned()) Ok(
cc.first()
.context(location_info!())?
.as_xsd_any_uri()
.context(location_info!())?
.to_owned(),
)
} }
pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>( pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
@ -139,9 +151,13 @@ where
Kind: Serialize, Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static, <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{ {
let cc = activity.cc().unwrap(); let cc = activity.cc().context(location_info!())?;
let cc = cc.as_many().unwrap(); let cc = cc.as_many().context(location_info!())?;
let community_followers_uri = cc.first().unwrap().as_xsd_any_uri().unwrap(); let community_followers_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 // TODO: this is hacky but seems to be the only way to get the community ID
let community_uri = community_followers_uri let community_uri = community_followers_uri
.to_string() .to_string()

View File

@ -20,6 +20,7 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use actix_web::{client::Client, web, HttpRequest, HttpResponse}; use actix_web::{client::Client, web, HttpRequest, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
community::{CommunityFollower, CommunityFollowerForm}, community::{CommunityFollower, CommunityFollowerForm},
naive_now, naive_now,
@ -29,6 +30,7 @@ use lemmy_db::{
Crud, Crud,
Followable, Followable,
}; };
use lemmy_utils::location_info;
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
@ -58,7 +60,10 @@ pub async fn user_inbox(
let username = path.into_inner(); let username = path.into_inner();
debug!("User {} received activity: {:?}", &username, &activity); debug!("User {} received activity: {:?}", &username, &activity);
let actor_uri = activity.actor()?.as_single_xsd_any_uri().unwrap(); let actor_uri = activity
.actor()?
.as_single_xsd_any_uri()
.context(location_info!())?;
check_is_apub_id_valid(actor_uri)?; check_is_apub_id_valid(actor_uri)?;
@ -66,7 +71,7 @@ pub async fn user_inbox(
verify(&request, actor.as_ref())?; verify(&request, actor.as_ref())?;
let any_base = activity.clone().into_any_base()?; let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap(); let kind = activity.kind().context(location_info!())?;
let res = match kind { let res = match kind {
ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await, ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await,
ValidTypes::Create => { ValidTypes::Create => {
@ -94,8 +99,12 @@ async fn receive_accept(
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let accept = Accept::from_any_base(activity)?.unwrap(); let accept = Accept::from_any_base(activity)?.context(location_info!())?;
let community_uri = accept.actor()?.to_owned().single_xsd_any_uri().unwrap(); let community_uri = accept
.actor()?
.to_owned()
.single_xsd_any_uri()
.context(location_info!())?;
let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?; let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?;
@ -123,10 +132,17 @@ async fn receive_create_private_message(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let create = Create::from_any_base(activity)?.unwrap(); let create = Create::from_any_base(activity)?.context(location_info!())?;
let note = Note::from_any_base(create.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(
create
.object()
.as_one()
.context(location_info!())?
.to_owned(),
)?
.context(location_info!())?;
let domain = Some(create.id_unchecked().unwrap().to_owned()); let domain = Some(create.id_unchecked().context(location_info!())?.to_owned());
let private_message = PrivateMessageForm::from_apub(&note, client, pool, domain).await?; let private_message = PrivateMessageForm::from_apub(&note, client, pool, domain).await?;
let inserted_private_message = blocking(pool, move |conn| { let inserted_private_message = blocking(pool, move |conn| {
@ -159,10 +175,17 @@ async fn receive_update_private_message(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let update = Update::from_any_base(activity)?.unwrap(); let update = Update::from_any_base(activity)?.context(location_info!())?;
let note = Note::from_any_base(update.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(
update
.object()
.as_one()
.context(location_info!())?
.to_owned(),
)?
.context(location_info!())?;
let domain = Some(update.id_unchecked().unwrap().to_owned()); let domain = Some(update.id_unchecked().context(location_info!())?.to_owned());
let private_message_form = PrivateMessageForm::from_apub(&note, client, pool, domain).await?; let private_message_form = PrivateMessageForm::from_apub(&note, client, pool, domain).await?;
let private_message_ap_id = private_message_form.ap_id.clone(); let private_message_ap_id = private_message_form.ap_id.clone();
@ -203,10 +226,17 @@ async fn receive_delete_private_message(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let delete = Delete::from_any_base(activity)?.unwrap(); let delete = Delete::from_any_base(activity)?.context(location_info!())?;
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(
delete
.object()
.as_one()
.context(location_info!())?
.to_owned(),
)?
.context(location_info!())?;
let domain = Some(delete.id_unchecked().unwrap().to_owned()); let domain = Some(delete.id_unchecked().context(location_info!())?.to_owned());
let private_message_form = PrivateMessageForm::from_apub(&note, client, pool, domain).await?; let private_message_form = PrivateMessageForm::from_apub(&note, client, pool, domain).await?;
let private_message_ap_id = private_message_form.ap_id; let private_message_ap_id = private_message_form.ap_id;
@ -259,11 +289,19 @@ async fn receive_undo_delete_private_message(
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let undo = Undo::from_any_base(activity)?.unwrap(); let undo = Undo::from_any_base(activity)?.context(location_info!())?;
let delete = Delete::from_any_base(undo.object().as_one().unwrap().to_owned())?.unwrap(); let delete = Delete::from_any_base(undo.object().as_one().context(location_info!())?.to_owned())?
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap(); .context(location_info!())?;
let note = Note::from_any_base(
delete
.object()
.as_one()
.context(location_info!())?
.to_owned(),
)?
.context(location_info!())?;
let domain = Some(undo.id_unchecked().unwrap().to_owned()); let domain = Some(undo.id_unchecked().context(location_info!())?.to_owned());
let private_message = PrivateMessageForm::from_apub(&note, client, pool, domain).await?; let private_message = PrivateMessageForm::from_apub(&note, client, pool, domain).await?;
let private_message_ap_id = private_message.ap_id.clone(); let private_message_ap_id = private_message.ap_id.clone();

View File

@ -30,10 +30,16 @@ use activitystreams::{
}; };
use activitystreams_ext::{Ext1, Ext2}; use activitystreams_ext::{Ext1, Ext2};
use actix_web::{body::Body, client::Client, HttpResponse}; use actix_web::{body::Body, client::Client, HttpResponse};
use anyhow::anyhow; use anyhow::{anyhow, Context};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use lemmy_db::{activity::do_insert_activity, user::User_}; use lemmy_db::{activity::do_insert_activity, user::User_};
use lemmy_utils::{convert_datetime, get_apub_protocol_string, settings::Settings, MentionData}; use lemmy_utils::{
convert_datetime,
get_apub_protocol_string,
location_info,
settings::Settings,
MentionData,
};
use log::debug; use log::debug;
use serde::Serialize; use serde::Serialize;
use url::{ParseError, Url}; use url::{ParseError, Url};
@ -80,7 +86,12 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
// instance. replace is needed to remove the port in our federation test setup. // instance. replace is needed to remove the port in our federation test setup.
let settings = Settings::get(); let settings = Settings::get();
let local_instance = settings.hostname.split(':').collect::<Vec<&str>>(); let local_instance = settings.hostname.split(':').collect::<Vec<&str>>();
allowed_instances.push(local_instance.first().unwrap().to_string()); allowed_instances.push(
local_instance
.first()
.context(location_info!())?
.to_string(),
);
match apub_id.domain() { match apub_id.domain() {
Some(d) => { Some(d) => {
@ -197,10 +208,10 @@ where
T: Base + AsBase<Kind>, T: Base + AsBase<Kind>,
{ {
let actor_id = if let Some(url) = expected_domain { let actor_id = if let Some(url) = expected_domain {
let domain = url.domain().unwrap(); let domain = url.domain().context(location_info!())?;
apub.id(domain)?.unwrap() apub.id(domain)?.context(location_info!())?
} else { } else {
let actor_id = apub.id_unchecked().unwrap(); let actor_id = apub.id_unchecked().context(location_info!())?;
check_is_apub_id_valid(&actor_id)?; check_is_apub_id_valid(&actor_id)?;
actor_id actor_id
}; };
@ -229,25 +240,13 @@ pub trait ApubLikeableType {
) -> Result<(), LemmyError>; ) -> Result<(), LemmyError>;
} }
pub fn get_shared_inbox(actor_id: &Url) -> String {
format!(
"{}://{}{}/inbox",
&actor_id.scheme(),
&actor_id.host_str().unwrap(),
if let Some(port) = actor_id.port() {
format!(":{}", port)
} else {
"".to_string()
},
)
}
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
pub trait ActorType { pub trait ActorType {
fn actor_id_str(&self) -> String; fn actor_id_str(&self) -> String;
fn public_key(&self) -> String; // TODO: every actor should have a public key, so this shouldnt be an option (needs to be fixed in db)
fn private_key(&self) -> String; fn public_key(&self) -> Option<String>;
fn private_key(&self) -> Option<String>;
/// numeric id in the database, used for insert_activity /// numeric id in the database, used for insert_activity
fn user_id(&self) -> i32; fn user_id(&self) -> i32;
@ -257,13 +256,13 @@ pub trait ActorType {
#[allow(unused_variables)] #[allow(unused_variables)]
async fn send_follow( async fn send_follow(
&self, &self,
follow_actor_id: &str, follow_actor_id: &Url,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<(), LemmyError>; ) -> Result<(), LemmyError>;
async fn send_unfollow( async fn send_unfollow(
&self, &self,
follow_actor_id: &str, follow_actor_id: &Url,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<(), LemmyError>; ) -> Result<(), LemmyError>;
@ -303,7 +302,7 @@ pub trait ActorType {
) -> Result<(), LemmyError>; ) -> Result<(), LemmyError>;
/// For a given community, returns the inboxes of all followers. /// For a given community, returns the inboxes of all followers.
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<String>, LemmyError>; async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
fn actor_id(&self) -> Result<Url, ParseError> { fn actor_id(&self) -> Result<Url, ParseError> {
Url::parse(&self.actor_id_str()) Url::parse(&self.actor_id_str())
@ -314,9 +313,19 @@ pub trait ActorType {
Url::parse(&format!("{}/inbox", &self.actor_id_str())) Url::parse(&format!("{}/inbox", &self.actor_id_str()))
} }
// TODO: make this return `Result<Url, ParseError> fn get_shared_inbox_url(&self) -> Result<Url, LemmyError> {
fn get_shared_inbox_url(&self) -> String { let actor_id = self.actor_id()?;
get_shared_inbox(&self.actor_id().unwrap()) let url = format!(
"{}://{}{}/inbox",
&actor_id.scheme(),

Cool, so we do get some url functionality out of this.

Cool, so we do get some url functionality out of this.

What do you mean get some url functionality?

What do you mean get some url functionality?
&actor_id.host_str().context(location_info!())?,
if let Some(port) = actor_id.port() {
format!(":{}", port)
} else {
"".to_string()
},
);
Ok(Url::parse(&url)?)
} }
fn get_outbox_url(&self) -> Result<Url, ParseError> { fn get_outbox_url(&self) -> Result<Url, ParseError> {
@ -335,13 +344,15 @@ pub trait ActorType {
format!("{}/liked", &self.actor_id_str()) format!("{}/liked", &self.actor_id_str())
} }
fn get_public_key_ext(&self) -> PublicKeyExtension { fn get_public_key_ext(&self) -> Result<PublicKeyExtension, LemmyError> {
Ok(
PublicKey { PublicKey {
id: format!("{}#main-key", self.actor_id_str()), id: format!("{}#main-key", self.actor_id_str()),
owner: self.actor_id_str(), owner: self.actor_id_str(),
public_key_pem: self.public_key(), public_key_pem: self.public_key().context(location_info!())?,

Nice, this is a pretty easy way to do this.

Nice, this is a pretty easy way to do this.
} }
.to_ext() .to_ext(),
)
} }
} }

View File

@ -32,19 +32,20 @@ use activitystreams::{
Update, Update,
}, },
context, context,
object::{kind::PageType, Image, Page, Tombstone}, object::{kind::PageType, Image, Object, Page, Tombstone},
prelude::*, prelude::*,
public, public,
}; };
use activitystreams_ext::Ext1; use activitystreams_ext::Ext1;
use actix_web::{body::Body, client::Client, web, HttpResponse}; use actix_web::{body::Body, client::Client, web, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
community::Community, community::Community,
post::{Post, PostForm}, post::{Post, PostForm},
user::User_, user::User_,
Crud, Crud,
}; };
use lemmy_utils::{convert_datetime, remove_slurs}; use lemmy_utils::{convert_datetime, location_info, remove_slurs};
use serde::Deserialize; use serde::Deserialize;
use url::Url; use url::Url;
@ -147,6 +148,50 @@ impl ToApub for Post {
} }
} }
struct EmbedType {

Is it possible to do this as a struct?

struct EmbedType {
  name: Option...
  summary:...
  content:...

Its a preference thing, but I really don't like tuple structs, and want to eliminate any others if we have them. You have to guess what that 2nd or 3rd item is, whereas with the regular structs, its a named thing so you know what it is.

Is it possible to do this as a struct? ``` struct EmbedType { name: Option... summary:... content:... ``` Its a preference thing, but I really don't like tuple structs, and want to eliminate any others if we have them. You have to guess what that 2nd or 3rd item is, whereas with the regular structs, its a named thing so you know what it is.

Sure I can do that, just added the typedef cause clippy was complaining.

Sure I can do that, just added the typedef cause clippy was complaining.
title: Option<String>,
description: Option<String>,
html: Option<String>,
}
fn extract_embed_from_apub(
page: &Ext1<Object<PageType>, PageExtension>,
) -> Result<EmbedType, LemmyError> {
match page.inner.preview() {
Some(preview) => {
let preview_page = Page::from_any_base(preview.one().context(location_info!())?.to_owned())?
.context(location_info!())?;
let title = preview_page
.name()
.map(|n| n.one())
.flatten()
.map(|s| s.as_xsd_string())
.flatten()
.map(|s| s.to_string());
let description = preview_page
.summary()
.map(|s| s.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
let html = preview_page
.content()
.map(|c| c.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
Ok(EmbedType {
title,
description,
html,
})
}
None => Ok(EmbedType {
title: None,
description: None,
html: None,
}),
}
}
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for PostForm { impl FromApub for PostForm {
type ApubType = PageExt; type ApubType = PageExt;
@ -163,9 +208,9 @@ impl FromApub for PostForm {
.inner .inner
.attributed_to() .attributed_to()
.as_ref() .as_ref()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.unwrap(); .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?; let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
@ -173,57 +218,52 @@ impl FromApub for PostForm {
.inner .inner
.to() .to()
.as_ref() .as_ref()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.unwrap(); .context(location_info!())?;
let community = get_or_fetch_and_upsert_community(community_actor_id, client, pool).await?; let community = get_or_fetch_and_upsert_community(community_actor_id, client, pool).await?;
let thumbnail_url = match &page.inner.image() { let thumbnail_url = match &page.inner.image() {
Some(any_image) => Image::from_any_base(any_image.to_owned().as_one().unwrap().to_owned())? Some(any_image) => Image::from_any_base(
.unwrap() any_image
.to_owned()
.as_one()
.context(location_info!())?
.to_owned(),
)?
.context(location_info!())?
.url() .url()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.map(|u| u.to_string()), .map(|u| u.to_string()),
None => None, None => None,
}; };
let (embed_title, embed_description, embed_html) = match page.inner.preview() { let embed = extract_embed_from_apub(page)?;
Some(preview) => {
let preview_page = Page::from_any_base(preview.one().unwrap().to_owned())?.unwrap();
let name = preview_page
.name()
.map(|n| n.as_one().unwrap().as_xsd_string().unwrap().to_string());
let summary = preview_page
.summary()
.map(|s| s.as_single_xsd_string().unwrap().to_string());
let content = preview_page
.content()
.map(|c| c.as_single_xsd_string().unwrap().to_string());
(name, summary, content)
}
None => (None, None, None),
};
let name = page let name = page
.inner .inner
.summary() .summary()
.as_ref() .as_ref()
.unwrap() .context(location_info!())?
.as_single_xsd_string() .as_single_xsd_string()
.unwrap() .context(location_info!())?
.to_string(); .to_string();
let url = page let url = page
.inner .inner
.url() .url()
.as_ref() .as_ref()
.map(|u| u.as_single_xsd_string().unwrap().to_string()); .map(|u| u.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
let body = page let body = page
.inner .inner
.content() .content()
.as_ref() .as_ref()
.map(|c| c.as_single_xsd_string().unwrap().to_string()); .map(|c| c.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
check_slurs(&name)?; check_slurs(&name)?;
let body_slurs_removed = body.map(|b| remove_slurs(&b)); let body_slurs_removed = body.map(|b| remove_slurs(&b));
Ok(PostForm { Ok(PostForm {
@ -247,9 +287,9 @@ impl FromApub for PostForm {
deleted: None, deleted: None,
nsfw: ext.sensitive, nsfw: ext.sensitive,
stickied: Some(ext.stickied), stickied: Some(ext.stickied),
embed_title, embed_title: embed.title,
embed_description, embed_description: embed.description,
embed_html, embed_html: embed.html,
thumbnail_url, thumbnail_url,
ap_id: check_actor_domain(page, expected_domain)?, ap_id: check_actor_domain(page, expected_domain)?,
local: false, local: false,
@ -281,7 +321,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
creator, creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
create.into_any_base()?, create.into_any_base()?,
client, client,
pool, pool,
@ -312,7 +352,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
creator, creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
update.into_any_base()?, update.into_any_base()?,
client, client,
pool, pool,
@ -342,7 +382,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
creator, creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
delete.into_any_base()?, delete.into_any_base()?,
client, client,
pool, pool,
@ -380,7 +420,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
creator, creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,
@ -410,7 +450,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
mod_, mod_,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
remove.into_any_base()?, remove.into_any_base()?,
client, client,
pool, pool,
@ -448,7 +488,7 @@ impl ApubObjectType for Post {
send_activity_to_community( send_activity_to_community(
mod_, mod_,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,
@ -481,7 +521,7 @@ impl ApubLikeableType for Post {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
like.into_any_base()?, like.into_any_base()?,
client, client,
pool, pool,
@ -511,7 +551,7 @@ impl ApubLikeableType for Post {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
dislike.into_any_base()?, dislike.into_any_base()?,
client, client,
pool, pool,
@ -549,7 +589,7 @@ impl ApubLikeableType for Post {
send_activity_to_community( send_activity_to_community(
&creator, &creator,
&community, &community,
vec![community.get_shared_inbox_url()], vec![community.get_shared_inbox_url()?],
undo.into_any_base()?, undo.into_any_base()?,
client, client,
pool, pool,

View File

@ -6,6 +6,7 @@ use crate::{
create_tombstone, create_tombstone,
fetcher::get_or_fetch_and_upsert_user, fetcher::get_or_fetch_and_upsert_user,
insert_activity, insert_activity,
ActorType,
ApubObjectType, ApubObjectType,
FromApub, FromApub,
ToApub, ToApub,
@ -27,12 +28,13 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use actix_web::client::Client; use actix_web::client::Client;
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
private_message::{PrivateMessage, PrivateMessageForm}, private_message::{PrivateMessage, PrivateMessageForm},
user::User_, user::User_,
Crud, Crud,
}; };
use lemmy_utils::convert_datetime; use lemmy_utils::{convert_datetime, location_info};
use url::Url; use url::Url;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
@ -81,15 +83,20 @@ impl FromApub for PrivateMessageForm {
) -> Result<PrivateMessageForm, LemmyError> { ) -> Result<PrivateMessageForm, LemmyError> {
let creator_actor_id = note let creator_actor_id = note
.attributed_to() .attributed_to()
.unwrap() .context(location_info!())?
.clone() .clone()
.single_xsd_any_uri() .single_xsd_any_uri()
.unwrap(); .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(&creator_actor_id, client, pool).await?; let creator = get_or_fetch_and_upsert_user(&creator_actor_id, client, pool).await?;
let recipient_actor_id = note.to().unwrap().clone().single_xsd_any_uri().unwrap(); let recipient_actor_id = note
.to()
.context(location_info!())?
.clone()
.single_xsd_any_uri()
.context(location_info!())?;
let recipient = get_or_fetch_and_upsert_user(&recipient_actor_id, client, pool).await?; let recipient = get_or_fetch_and_upsert_user(&recipient_actor_id, client, pool).await?;
let ap_id = note.id_unchecked().unwrap().to_string(); let ap_id = note.id_unchecked().context(location_info!())?.to_string();
check_is_apub_id_valid(&Url::parse(&ap_id)?)?; check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
Ok(PrivateMessageForm { Ok(PrivateMessageForm {
@ -97,9 +104,9 @@ impl FromApub for PrivateMessageForm {
recipient_id: recipient.id, recipient_id: recipient.id,
content: note content: note
.content() .content()
.unwrap() .context(location_info!())?
.as_single_xsd_string() .as_single_xsd_string()
.unwrap() .context(location_info!())?
.to_string(), .to_string(),
published: note.published().map(|u| u.to_owned().naive_local()), published: note.published().map(|u| u.to_owned().naive_local()),
updated: note.updated().map(|u| u.to_owned().naive_local()), updated: note.updated().map(|u| u.to_owned().naive_local()),
@ -126,7 +133,7 @@ impl ApubObjectType for PrivateMessage {
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??; let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
let mut create = Create::new(creator.actor_id.to_owned(), note.into_any_base()?); let mut create = Create::new(creator.actor_id.to_owned(), note.into_any_base()?);
let to = format!("{}/inbox", recipient.actor_id); let to = recipient.get_inbox_url()?;
create create
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(CreateType::Create)?) .set_id(generate_activity_id(CreateType::Create)?)
@ -151,7 +158,7 @@ impl ApubObjectType for PrivateMessage {
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??; let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
let mut update = Update::new(creator.actor_id.to_owned(), note.into_any_base()?); let mut update = Update::new(creator.actor_id.to_owned(), note.into_any_base()?);
let to = format!("{}/inbox", recipient.actor_id); let to = recipient.get_inbox_url()?;
update update
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(UpdateType::Update)?) .set_id(generate_activity_id(UpdateType::Update)?)
@ -175,7 +182,7 @@ impl ApubObjectType for PrivateMessage {
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??; let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?); let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
let to = format!("{}/inbox", recipient.actor_id); let to = recipient.get_inbox_url()?;
delete delete
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(DeleteType::Delete)?) .set_id(generate_activity_id(DeleteType::Delete)?)
@ -199,7 +206,7 @@ impl ApubObjectType for PrivateMessage {
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??; let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?); let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
let to = format!("{}/inbox", recipient.actor_id); let to = recipient.get_inbox_url()?;
delete delete
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(DeleteType::Delete)?) .set_id(generate_activity_id(DeleteType::Delete)?)

View File

@ -4,6 +4,7 @@ use crate::{
activities::{generate_activity_id, send_activity}, activities::{generate_activity_id, send_activity},
check_actor_domain, check_actor_domain,
create_apub_response, create_apub_response,
fetcher::get_or_fetch_and_upsert_actor,
insert_activity, insert_activity,
ActorType, ActorType,
FromApub, FromApub,
@ -28,11 +29,12 @@ use activitystreams::{
}; };
use activitystreams_ext::Ext1; use activitystreams_ext::Ext1;
use actix_web::{body::Body, client::Client, web, HttpResponse}; use actix_web::{body::Body, client::Client, web, HttpResponse};
use anyhow::Context;
use lemmy_db::{ use lemmy_db::{
naive_now, naive_now,
user::{UserForm, User_}, user::{UserForm, User_},
}; };
use lemmy_utils::convert_datetime; use lemmy_utils::{convert_datetime, location_info};
use serde::Deserialize; use serde::Deserialize;
use url::Url; use url::Url;
@ -82,7 +84,7 @@ impl ToApub for User_ {
.set_following(self.get_following_url().parse()?) .set_following(self.get_following_url().parse()?)
.set_liked(self.get_liked_url().parse()?) .set_liked(self.get_liked_url().parse()?)
.set_endpoints(Endpoints { .set_endpoints(Endpoints {
shared_inbox: Some(self.get_shared_inbox_url().parse()?), shared_inbox: Some(self.get_shared_inbox_url()?),
..Default::default() ..Default::default()
}); });
@ -90,7 +92,7 @@ impl ToApub for User_ {
ap_actor.set_preferred_username(i.to_owned()); ap_actor.set_preferred_username(i.to_owned());
} }
Ok(Ext1::new(ap_actor, self.get_public_key_ext())) Ok(Ext1::new(ap_actor, self.get_public_key_ext()?))
} }
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> { fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
unimplemented!() unimplemented!()
@ -103,26 +105,27 @@ impl ActorType for User_ {
self.actor_id.to_owned() self.actor_id.to_owned()
} }
fn public_key(&self) -> String { fn public_key(&self) -> Option<String> {
self.public_key.to_owned().unwrap() self.public_key.to_owned()
} }
fn private_key(&self) -> String { fn private_key(&self) -> Option<String> {
self.private_key.to_owned().unwrap() self.private_key.to_owned()
} }
/// As a given local user, send out a follow request to a remote community. /// As a given local user, send out a follow request to a remote community.
async fn send_follow( async fn send_follow(
&self, &self,
follow_actor_id: &str, follow_actor_id: &Url,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id); let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id.as_str());
follow follow
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(FollowType::Follow)?); .set_id(generate_activity_id(FollowType::Follow)?);
let to = format!("{}/inbox", follow_actor_id); let follow_actor = get_or_fetch_and_upsert_actor(follow_actor_id, client, pool).await?;
let to = follow_actor.get_inbox_url()?;
insert_activity(self.id, follow.clone(), true, pool).await?; insert_activity(self.id, follow.clone(), true, pool).await?;
@ -132,16 +135,17 @@ impl ActorType for User_ {
async fn send_unfollow( async fn send_unfollow(
&self, &self,
follow_actor_id: &str, follow_actor_id: &Url,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id); let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id.as_str());
follow follow
.set_context(context()) .set_context(context())
.set_id(generate_activity_id(FollowType::Follow)?); .set_id(generate_activity_id(FollowType::Follow)?);
let follow_actor = get_or_fetch_and_upsert_actor(follow_actor_id, client, pool).await?;
let to = format!("{}/inbox", follow_actor_id); let to = follow_actor.get_inbox_url()?;
// Undo that fake activity // Undo that fake activity
let mut undo = Undo::new(Url::parse(&self.actor_id)?, follow.into_any_base()?); let mut undo = Undo::new(Url::parse(&self.actor_id)?, follow.into_any_base()?);
@ -200,7 +204,7 @@ impl ActorType for User_ {
unimplemented!() unimplemented!()
} }
async fn get_follower_inboxes(&self, _pool: &DbPool) -> Result<Vec<String>, LemmyError> { async fn get_follower_inboxes(&self, _pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
unimplemented!() unimplemented!()
} }
@ -221,11 +225,10 @@ impl FromApub for UserForm {
) -> Result<Self, LemmyError> { ) -> Result<Self, LemmyError> {
let avatar = match person.icon() { let avatar = match person.icon() {
Some(any_image) => Some( Some(any_image) => Some(
Image::from_any_base(any_image.as_one().unwrap().clone()) Image::from_any_base(any_image.as_one().context(location_info!())?.clone())?
.unwrap() .context(location_info!())?
.unwrap()
.url() .url()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.map(|u| u.to_string()), .map(|u| u.to_string()),
), ),
@ -234,11 +237,11 @@ impl FromApub for UserForm {
let banner = match person.image() { let banner = match person.image() {
Some(any_image) => Some( Some(any_image) => Some(
Image::from_any_base(any_image.as_one().unwrap().clone()) Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
.unwrap() .context(location_info!())?
.unwrap() .context(location_info!())?
.url() .url()
.unwrap() .context(location_info!())?
.as_single_xsd_any_uri() .as_single_xsd_any_uri()
.map(|u| u.to_string()), .map(|u| u.to_string()),
), ),
@ -247,17 +250,19 @@ impl FromApub for UserForm {
let name = person let name = person
.name() .name()
.unwrap() .context(location_info!())?
.one() .one()
.unwrap() .context(location_info!())?
.as_xsd_string() .as_xsd_string()
.unwrap() .context(location_info!())?
.to_string(); .to_string();
let preferred_username = person.inner.preferred_username().map(|u| u.to_string()); let preferred_username = person.inner.preferred_username().map(|u| u.to_string());
let bio = person let bio = person
.inner .inner
.summary() .summary()
.map(|s| s.as_single_xsd_string().unwrap().into()); .map(|s| s.as_single_xsd_string())
.flatten()
.map(|s| s.to_string());
check_slurs(&name)?; check_slurs(&name)?;
check_slurs_opt(&preferred_username)?; check_slurs_opt(&preferred_username)?;
check_slurs_opt(&bio)?; check_slurs_opt(&bio)?;