Community outbox should only contain activities sent by community (fixes #1916)

This commit is contained in:
Felix Ableitner 2021-11-18 18:04:28 +01:00
parent 8fc252ec55
commit a2707e1c56
5 changed files with 63 additions and 199 deletions

View file

@ -1,209 +1,61 @@
{ {
"type": "OrderedCollection", "type": "OrderedCollection",
"id": "https://ds9.lemmy.ml/c/main/outbox", "id": "https://ds9.lemmy.ml/c/testcom/outbox",
"totalItems": 7, "totalItems": 2,
"orderedItems": [ "orderedItems": [
{ {
"actor": "https://ds9.lemmy.ml/u/dess_ds9", "actor": "https://ds9.lemmy.ml/c/testcom",
"to": [ "to": [
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
"object": { "object": {
"type": "Page", "type": "Page",
"id": "https://ds9.lemmy.ml/post/1685", "id": "https://ds9.lemmy.ml/post/2328",
"attributedTo": "https://ds9.lemmy.ml/u/dess_ds9",
"to": [
"https://ds9.lemmy.ml/c/main",
"https://www.w3.org/ns/activitystreams#Public"
],
"name": "Test post",
"mediaType": "text/html",
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
"published": "2021-09-30T16:37:58.425718+00:00",
"updated": "2021-09-30T16:39:50.934055+00:00"
},
"cc": [
"https://ds9.lemmy.ml/c/main"
],
"type": "Create",
"id": "https://ds9.lemmy.ml/activities/create/157bc329-05cb-4dc3-ad9e-5110fde3f3aa"
},
{
"actor": "https://ds9.lemmy.ml/u/nutomic",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"object": {
"type": "Page",
"id": "https://ds9.lemmy.ml/post/1665",
"attributedTo": "https://ds9.lemmy.ml/u/nutomic", "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
"to": [ "to": [
"https://ds9.lemmy.ml/c/main", "https://ds9.lemmy.ml/c/testcom",
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
"name": "another webmention test", "cc": [],
"name": "another outbox test",
"mediaType": "text/html", "mediaType": "text/html",
"url": "https://webmention.rocks/test/1",
"commentsEnabled": true, "commentsEnabled": true,
"sensitive": false, "sensitive": false,
"stickied": false, "stickied": false,
"published": "2021-09-17T13:22:15.026912+00:00" "published": "2021-11-18T17:19:45.895163+00:00"
}, },
"cc": [ "cc": [
"https://ds9.lemmy.ml/c/main" "https://ds9.lemmy.ml/c/testcom/followers"
], ],
"type": "Create", "type": "Announce",
"id": "https://ds9.lemmy.ml/activities/create/c54e4509-16ac-42bf-b3b4-0bf8516f8152" "id": "https://ds9.lemmy.ml/activities/announce/b204fe9f-b13d-4af2-9d22-239ac2d892e6"
}, },
{ {
"actor": "https://ds9.lemmy.ml/u/nutomic", "actor": "https://ds9.lemmy.ml/c/testcom",
"to": [ "to": [
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
"object": { "object": {
"type": "Page", "type": "Page",
"id": "https://ds9.lemmy.ml/post/1664", "id": "https://ds9.lemmy.ml/post/2327",
"attributedTo": "https://ds9.lemmy.ml/u/nutomic", "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
"to": [ "to": [
"https://ds9.lemmy.ml/c/main", "https://ds9.lemmy.ml/c/testcom",
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
"name": "another test", "cc": [],
"mediaType": "text/html", "name": "outbox test",
"url": "https://webmention.rocks/test/1",
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
"published": "2021-09-17T13:13:21.675891+00:00"
},
"cc": [
"https://ds9.lemmy.ml/c/main"
],
"type": "Create",
"id": "https://ds9.lemmy.ml/activities/create/25f7d2cb-11d5-4c9c-aa3c-85fbff9f9e0c"
},
{
"actor": "https://ds9.lemmy.ml/u/nutomic",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"object": {
"type": "Page",
"id": "https://ds9.lemmy.ml/post/1663",
"attributedTo": "https://ds9.lemmy.ml/u/nutomic",
"to": [
"https://ds9.lemmy.ml/c/main",
"https://www.w3.org/ns/activitystreams#Public"
],
"name": "Webmention test from Lemmy",
"mediaType": "text/html",
"url": "https://webmention.rocks/test/1",
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
"published": "2021-09-17T13:00:15.392844+00:00"
},
"cc": [
"https://ds9.lemmy.ml/c/main"
],
"type": "Create",
"id": "https://ds9.lemmy.ml/activities/create/cfbd12b8-2e11-42b6-a609-b482decbaf11"
},
{
"actor": "https://ds9.lemmy.ml/u/dess_tester_3",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"object": {
"type": "Page",
"id": "https://ds9.lemmy.ml/post/1644",
"attributedTo": "https://ds9.lemmy.ml/u/dess_tester_3",
"to": [
"https://ds9.lemmy.ml/c/main",
"https://www.w3.org/ns/activitystreams#Public"
],
"name": "The best wireless earbuds you can buy right now | Engadget",
"mediaType": "text/html",
"url": "https://www.engadget.com/best-wireless-earbuds-120058222.html",
"image": {
"type": "Image",
"url": "https://ds9.lemmy.ml/pictrs/image/0WWsYOuwAE.jpg"
},
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
"published": "2021-08-26T01:22:06.428368+00:00"
},
"cc": [
"https://ds9.lemmy.ml/c/main"
],
"type": "Create",
"id": "https://ds9.lemmy.ml/activities/create/76c94408-944a-4a2f-a88b-d10f12b472b0"
},
{
"actor": "https://ds9.lemmy.ml/u/dess_ds9",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"object": {
"type": "Page",
"id": "https://ds9.lemmy.ml/post/1643",
"attributedTo": "https://ds9.lemmy.ml/u/dess_ds9",
"to": [
"https://ds9.lemmy.ml/c/main",
"https://www.w3.org/ns/activitystreams#Public"
],
"name": "First Look: Cadillacs luxury EV debut seems like a winner | Engadges",
"content": "<p>test</p>\n",
"mediaType": "text/html",
"source": {
"content": "test",
"mediaType": "text/markdown"
},
"url": "https://www.engadget.com/cadillac-lyriq-luxury-ev-first-look-video-171543752.html",
"image": {
"type": "Image",
"url": "https://ds9.lemmy.ml/pictrs/image/gnmtvgXP31.jpg"
},
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
"published": "2021-08-23T23:43:06.560543+00:00",
"updated": "2021-08-23T23:52:51.832606+00:00"
},
"cc": [
"https://ds9.lemmy.ml/c/main"
],
"type": "Create",
"id": "https://ds9.lemmy.ml/activities/create/b1f95918-f593-4951-91cf-2c3340cd9509"
},
{
"actor": "https://ds9.lemmy.ml/u/dess_ds9_2",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"object": {
"type": "Page",
"id": "https://ds9.lemmy.ml/post/1642",
"attributedTo": "https://ds9.lemmy.ml/u/dess_ds9_2",
"to": [
"https://ds9.lemmy.ml/c/main",
"https://www.w3.org/ns/activitystreams#Public"
],
"name": "A test post from DS9",
"mediaType": "text/html", "mediaType": "text/html",
"commentsEnabled": true, "commentsEnabled": true,
"sensitive": false, "sensitive": false,
"stickied": false, "stickied": false,
"published": "2021-08-06T14:10:47.493075+00:00" "published": "2021-11-18T17:19:05.763109+00:00"
}, },
"cc": [ "cc": [
"https://ds9.lemmy.ml/c/main" "https://ds9.lemmy.ml/c/testcom/followers"
], ],
"type": "Create", "type": "Announce",
"id": "https://ds9.lemmy.ml/activities/create/6359b2e7-badb-4241-b5ee-b093078361bd" "id": "https://ds9.lemmy.ml/activities/announce/c6c960ce-c8d8-4231-925e-3ba367468f18"
} }
] ]
} }

View file

@ -25,7 +25,7 @@ pub(crate) trait GetCommunity {
} }
impl AnnounceActivity { impl AnnounceActivity {
fn new( pub(crate) fn new(
object: AnnouncableActivities, object: AnnouncableActivities,
community: &ApubCommunity, community: &ApubCommunity,
context: &LemmyContext, context: &LemmyContext,
@ -103,13 +103,20 @@ impl ActivityHandler for AnnounceActivity {
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
request_counter: &mut i32, request_counter: &mut i32,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let object_value = serde_json::to_value(&self.object)?; // TODO: this can probably be implemented in a cleaner way
let object_data: ActivityCommonFields = serde_json::from_value(object_value.to_owned())?; match self.object {
// Dont insert these into activities table, as they are not activities.
AnnouncableActivities::Page(_) | AnnouncableActivities::Note(_) => {}
_ => {
let object_value = serde_json::to_value(&self.object)?;
let object_data: ActivityCommonFields = serde_json::from_value(object_value.to_owned())?;
if is_activity_already_known(context.pool(), &object_data.id).await? { if is_activity_already_known(context.pool(), &object_data.id).await? {
return Ok(()); return Ok(());
}
insert_activity(&object_data.id, object_value, false, true, context.pool()).await?;
}
} }
insert_activity(&object_data.id, object_value, false, true, context.pool()).await?;
self.object.receive(context, request_counter).await self.object.receive(context, request_counter).await
} }
} }

View file

@ -1,9 +1,10 @@
use crate::{ use crate::{
activity_lists::AnnouncableActivities,
collections::CommunityContext, collections::CommunityContext,
generate_outbox_url, generate_outbox_url,
objects::{person::ApubPerson, post::ApubPost}, objects::post::ApubPost,
protocol::{ protocol::{
activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType}, activities::community::announce::AnnounceActivity,
collections::group_outbox::GroupOutbox, collections::group_outbox::GroupOutbox,
}, },
}; };
@ -15,10 +16,7 @@ use lemmy_apub_lib::{
traits::{ActivityHandler, ApubObject}, traits::{ActivityHandler, ApubObject},
verify::verify_domains_match, verify::verify_domains_match,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::source::post::Post;
source::{person::Person, post::Post},
traits::Crud,
};
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use url::Url; use url::Url;
@ -63,13 +61,10 @@ impl ApubObject for ApubCommunityOutbox {
async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> { async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
let mut ordered_items = vec![]; let mut ordered_items = vec![];
for post in self.0 { for post in self.0 {
let actor = post.creator_id; let page = post.into_apub(&data.1).await?;
let actor: ApubPerson = blocking(data.1.pool(), move |conn| Person::read(conn, actor)) let announcable = AnnouncableActivities::Page(page);
.await?? let announce = AnnounceActivity::new(announcable, &data.0, &data.1)?;
.into(); ordered_items.push(announce);
let a =
CreateOrUpdatePost::new(post, &actor, &data.0, CreateOrUpdateType::Create, &data.1).await?;
ordered_items.push(a);
} }
Ok(GroupOutbox { Ok(GroupOutbox {
@ -108,11 +103,12 @@ impl ApubObject for ApubCommunityOutbox {
// We intentionally ignore errors here. This is because the outbox might contain posts from old // We intentionally ignore errors here. This is because the outbox might contain posts from old
// Lemmy versions, or from other software which we cant parse. In that case, we simply skip the // Lemmy versions, or from other software which we cant parse. In that case, we simply skip the
// item and only parse the ones that work. // item and only parse the ones that work.
let data = Data::new(data.1.clone());
for activity in outbox_activities { for activity in outbox_activities {
activity let verify = activity.verify(&data, request_counter).await;
.receive(&Data::new(data.1.clone()), request_counter) if verify.is_ok() {
.await activity.receive(&data, request_counter).await.ok();
.ok(); }
} }
// This return value is unused, so just set an empty vec // This return value is unused, so just set an empty vec

View file

@ -1,4 +1,4 @@
use crate::protocol::activities::create_or_update::post::CreateOrUpdatePost; use crate::protocol::activities::community::announce::AnnounceActivity;
use activitystreams::collection::kind::OrderedCollectionType; use activitystreams::collection::kind::OrderedCollectionType;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -9,5 +9,5 @@ pub struct GroupOutbox {
pub(crate) r#type: OrderedCollectionType, pub(crate) r#type: OrderedCollectionType,
pub(crate) id: Url, pub(crate) id: Url,
pub(crate) total_items: i32, pub(crate) total_items: i32,
pub(crate) ordered_items: Vec<CreateOrUpdatePost>, pub(crate) ordered_items: Vec<AnnounceActivity>,
} }

View file

@ -8,7 +8,7 @@ use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::{ use lemmy_apub_lib::{
data::Data, data::Data,
object_id::ObjectId, object_id::ObjectId,
traits::ActivityHandler, traits::{ActivityHandler, ApubObject},
values::MediaTypeHtml, values::MediaTypeHtml,
}; };
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
@ -79,14 +79,23 @@ impl Page {
} }
} }
// For Pleroma/Mastodon compat. Unimplemented because its only used for sending. // Used for community outbox, so that it can be compatible with Pleroma/Mastodon.
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for Page { impl ActivityHandler for Page {
type DataType = LemmyContext; type DataType = LemmyContext;
async fn verify(&self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> { async fn verify(
Err(anyhow!("Announce/Page can only be sent, not received").into()) &self,
data: &Data<Self::DataType>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
ApubPost::verify(self, self.id.inner(), data, request_counter).await
} }
async fn receive(self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> { async fn receive(
unimplemented!() self,
data: &Data<Self::DataType>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
ApubPost::from_apub(self, data, request_counter).await?;
Ok(())
} }
} }