Simplify inbox

This commit is contained in:
Felix Ableitner 2021-08-15 15:41:29 +02:00
parent 4e840a9527
commit ddf1db0980
5 changed files with 93 additions and 101 deletions

View file

@ -29,6 +29,7 @@ use url::Url;
#[serde(rename_all = "camelCase")]
pub struct UpdateCommunity {
to: PublicUrl,
// TODO: would be nice to use a separate struct here, which only contains the fields updated here
object: Group,
cc: [Url; 1],
#[serde(rename = "type")]

View file

@ -1,10 +1,13 @@
use crate::{
activities::{
community::announce::AnnouncableActivities,
following::{follow::FollowCommunity, undo::UndoFollowCommunity},
},
extensions::context::lemmy_context,
generate_moderators_url,
http::{
create_apub_response,
create_apub_tombstone_response,
inbox_enums::GroupInboxActivities,
payload_to_string,
receive_activity,
},
@ -18,6 +21,7 @@ use activitystreams::{
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::source::{activity::Activity_, community::Community_};
use lemmy_db_schema::source::{activity::Activity, community::Community};
use lemmy_db_views_actor::{
@ -26,7 +30,8 @@ use lemmy_db_views_actor::{
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
use log::trace;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
pub(crate) struct CommunityQuery {
@ -52,6 +57,14 @@ pub(crate) async fn get_apub_community_http(
}
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum GroupInboxActivities {
FollowCommunity(FollowCommunity),
UndoFollowCommunity(UndoFollowCommunity),
AnnouncableActivities(AnnouncableActivities),
}
/// Handler for all incoming receive to community inboxes.
pub async fn community_inbox(
request: HttpRequest,
@ -60,7 +73,18 @@ pub async fn community_inbox(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
receive_activity::<GroupInboxActivities>(request, &unparsed, context).await
trace!("Received community inbox activity {}", unparsed);
let activity = serde_json::from_str::<GroupInboxActivities>(&unparsed)?;
receive_group_inbox(activity.clone(), request, context).await
}
pub(in crate::http) async fn receive_group_inbox(
activity: GroupInboxActivities,
request: HttpRequest,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
receive_activity(request, activity.clone(), context.get_ref()).await
}
/// Returns an empty followers collection, only populating the size (for privacy).

View file

@ -1,82 +0,0 @@
use crate::activities::{
comment::create_or_update::CreateOrUpdateComment,
community::{
add_mod::AddMod,
announce::AnnounceActivity,
block_user::BlockUserFromCommunity,
remove_mod::RemoveMod,
undo_block_user::UndoBlockUserFromCommunity,
update::UpdateCommunity,
},
deletion::{delete::Delete, undo_delete::UndoDelete},
following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity},
post::create_or_update::CreateOrUpdatePost,
private_message::{
create_or_update::CreateOrUpdatePrivateMessage,
delete::DeletePrivateMessage,
undo_delete::UndoDeletePrivateMessage,
},
undo_remove::UndoRemovePostCommentOrCommunity,
voting::{undo_vote::UndoVote, vote::Vote},
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum PersonInboxActivities {
AcceptFollowCommunity(AcceptFollowCommunity),
CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
DeletePrivateMessage(DeletePrivateMessage),
UndoDeletePrivateMessage(UndoDeletePrivateMessage),
AnnounceActivity(Box<AnnounceActivity>),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum GroupInboxActivities {
FollowCommunity(FollowCommunity),
UndoFollowCommunity(UndoFollowCommunity),
CreateOrUpdateComment(CreateOrUpdateComment),
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
Vote(Vote),
UndoVote(UndoVote),
DeletePostCommentOrCommunity(Delete),
UndoDeletePostCommentOrCommunity(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
RemoveMod(RemoveMod),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum SharedInboxActivities {
// received by group
FollowCommunity(FollowCommunity),
UndoFollowCommunity(UndoFollowCommunity),
CreateOrUpdateComment(CreateOrUpdateComment),
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
Vote(Vote),
UndoVote(UndoVote),
Delete(Delete),
UndoDelete(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
RemoveMod(RemoveMod),
// received by person
AcceptFollowCommunity(AcceptFollowCommunity),
// Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
// avoid this problem by replacing createpm.object with our own struct, instead of NoteExt.
CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
DeletePrivateMessage(DeletePrivateMessage),
UndoDeletePrivateMessage(UndoDeletePrivateMessage),
AnnounceActivity(Box<AnnounceActivity>),
}

View file

@ -2,7 +2,10 @@ use crate::{
check_is_apub_id_valid,
extensions::signatures::verify_signature,
fetcher::get_or_fetch_and_upsert_actor,
http::inbox_enums::SharedInboxActivities,
http::{
community::{receive_group_inbox, GroupInboxActivities},
person::{receive_person_inbox, PersonInboxActivities},
},
insert_activity,
APUB_JSON_CONTENT_TYPE,
};
@ -17,29 +20,47 @@ use anyhow::{anyhow, Context};
use futures::StreamExt;
use http::StatusCode;
use lemmy_api_common::blocking;
use lemmy_apub_lib::ActivityHandler;
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::{source::activity::Activity_, DbPool};
use lemmy_db_schema::source::activity::Activity;
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{info, trace};
use serde::{Deserialize, Serialize};
use std::{fmt::Debug, io::Read};
use url::Url;
mod comment;
mod community;
mod inbox_enums;
mod person;
mod post;
pub mod routes;
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum SharedInboxActivities {
GroupInboxActivities(GroupInboxActivities),
// Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
// avoid this problem by replacing createpm.object with our own struct, instead of NoteExt.
PersonInboxActivities(PersonInboxActivities),
}
pub async fn shared_inbox(
request: HttpRequest,
payload: Payload,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
receive_activity::<SharedInboxActivities>(request, &unparsed, context).await
trace!("Received shared inbox activity {}", unparsed);
let activity = serde_json::from_str::<SharedInboxActivities>(&unparsed)?;
match activity {
SharedInboxActivities::GroupInboxActivities(g) => {
receive_group_inbox(g, request, context).await
}
SharedInboxActivities::PersonInboxActivities(p) => {
receive_person_inbox(p, request, context).await
}
}
}
async fn payload_to_string(mut payload: Payload) -> Result<String, LemmyError> {
@ -55,18 +76,16 @@ async fn payload_to_string(mut payload: Payload) -> Result<String, LemmyError> {
// TODO: move most of this code to library
async fn receive_activity<'a, T>(
request: HttpRequest,
activity: &'a str,
context: web::Data<LemmyContext>,
activity: T,
context: &LemmyContext,
) -> Result<HttpResponse, LemmyError>
where
T: ActivityHandler + Clone + Deserialize<'a> + Serialize + std::fmt::Debug + Send + 'static,
{
let activity = serde_json::from_str::<T>(activity)?;
let activity_data = activity.common();
let request_counter = &mut 0;
let actor =
get_or_fetch_and_upsert_actor(&activity_data.actor, &context, request_counter).await?;
let actor = get_or_fetch_and_upsert_actor(&activity_data.actor, context, request_counter).await?;
verify_signature(&request, &actor.public_key().context(location_info!())?)?;
// Do nothing if we received the same activity before
@ -74,11 +93,11 @@ where
return Ok(HttpResponse::Ok().finish());
}
check_is_apub_id_valid(&activity_data.actor, false)?;
println!(
info!(
"Verifying activity {}",
activity_data.id_unchecked().to_string()
);
activity.verify(&context, request_counter).await?;
activity.verify(context, request_counter).await?;
assert_activity_not_local(&activity)?;
// Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen
@ -92,11 +111,11 @@ where
)
.await?;
println!(
info!(
"Receiving activity {}",
activity_data.id_unchecked().to_string()
);
activity.receive(&context, request_counter).await?;
activity.receive(context, request_counter).await?;
Ok(HttpResponse::Ok().finish())
}

View file

@ -1,9 +1,17 @@
use crate::{
activities::{
community::announce::AnnounceActivity,
following::accept::AcceptFollowCommunity,
private_message::{
create_or_update::CreateOrUpdatePrivateMessage,
delete::DeletePrivateMessage,
undo_delete::UndoDeletePrivateMessage,
},
},
extensions::context::lemmy_context,
http::{
create_apub_response,
create_apub_tombstone_response,
inbox_enums::PersonInboxActivities,
payload_to_string,
receive_activity,
},
@ -16,11 +24,13 @@ use activitystreams::{
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::source::person::Person_;
use lemmy_db_schema::source::person::Person;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
use log::trace;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Deserialize)]
@ -49,6 +59,16 @@ pub(crate) async fn get_apub_person_http(
}
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
#[serde(untagged)]
pub enum PersonInboxActivities {
AcceptFollowCommunity(AcceptFollowCommunity),
CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
DeletePrivateMessage(DeletePrivateMessage),
UndoDeletePrivateMessage(UndoDeletePrivateMessage),
AnnounceActivity(Box<AnnounceActivity>),
}
pub async fn person_inbox(
request: HttpRequest,
payload: Payload,
@ -56,7 +76,17 @@ pub async fn person_inbox(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
receive_activity::<PersonInboxActivities>(request, &unparsed, context).await
trace!("Received person inbox activity {}", unparsed);
let activity = serde_json::from_str::<PersonInboxActivities>(&unparsed)?;
receive_person_inbox(activity, request, context).await
}
pub(in crate::http) async fn receive_person_inbox(
activity: PersonInboxActivities,
request: HttpRequest,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
receive_activity(request, activity, context.get_ref()).await
}
pub(crate) async fn get_apub_person_outbox(