mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-23 11:21:32 +00:00
Handle federated reports from Mastodon, Kbin (#4323)
* Test Kbin/Mbin federation * Handle reports from Mastodon/Kbin (fixes #4217) * prettier * revert * add mastodon activity * ci * revert * ci
This commit is contained in:
parent
4ca63c5641
commit
e3b715002b
8 changed files with 102 additions and 13 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
|||
|
||||
[[package]]
|
||||
name = "activitypub_federation"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1-beta.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bac58c1d61b6e2358adbd043c78ba853428102b489acb7b6cb74ee6f2ae668f"
|
||||
checksum = "866db431760d14a7360f12e75ad48f3265b5b89cd2303e548a02bcc8983e4fcd"
|
||||
dependencies = [
|
||||
"activitystreams-kinds",
|
||||
"actix-web",
|
||||
|
|
|
@ -95,7 +95,7 @@ lemmy_routes = { version = "=0.19.2-rc.2", path = "./crates/routes" }
|
|||
lemmy_db_views = { version = "=0.19.2-rc.2", path = "./crates/db_views" }
|
||||
lemmy_db_views_actor = { version = "=0.19.2-rc.2", path = "./crates/db_views_actor" }
|
||||
lemmy_db_views_moderator = { version = "=0.19.2-rc.2", path = "./crates/db_views_moderator" }
|
||||
activitypub_federation = { version = "0.5.0", default-features = false, features = [
|
||||
activitypub_federation = { version = "0.5.1-beta.1", default-features = false, features = [
|
||||
"actix-web",
|
||||
] }
|
||||
diesel = "2.1.4"
|
||||
|
|
13
crates/apub/assets/mastodon/activities/flag.json
Normal file
13
crates/apub/assets/mastodon/activities/flag.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://mastodon.example/ccb4f39a-506a-490e-9a8c-71831c7713a4",
|
||||
"type": "Flag",
|
||||
"actor": "https://mastodon.example/actor",
|
||||
"content": "Please take a look at this user and their posts",
|
||||
"object": [
|
||||
"https://example.com/users/1",
|
||||
"https://example.com/posts/380590",
|
||||
"https://example.com/posts/380591"
|
||||
],
|
||||
"to": "https://example.com/users/1"
|
||||
}
|
12
crates/apub/assets/mbin/activities/accept.json
Normal file
12
crates/apub/assets/mbin/activities/accept.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://some-mbin.instance/f/object/2721ffc3-f8a9-417e-a124-af057434a3af#accept",
|
||||
"type": "Accept",
|
||||
"actor": "https://some-mbin.instance/m/someMag",
|
||||
"object": {
|
||||
"id": "https://some-other.instance/f/object/c51ea652-e594-4920-a989-f5350f0cec05",
|
||||
"type": "Follow",
|
||||
"actor": "https://some-other.instance/u/someUser",
|
||||
"object": "https://some-mbin.instance/m/someMag"
|
||||
}
|
||||
}
|
11
crates/apub/assets/mbin/activities/flag.json
Normal file
11
crates/apub/assets/mbin/activities/flag.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"@context": ["https://www.w3.org/ns/activitystreams"],
|
||||
"id": "https://mbin-test1/reports/45f8a01d-a73e-4575-bffa-c9f24c61f458",
|
||||
"type": "Flag",
|
||||
"actor": "https://mbin-test1/u/BentiGorlich",
|
||||
"object": ["https://lemmy-test/post/4", "https://lemmy-test/u/BentiGorlich"],
|
||||
"audience": "https://lemmy-test/c/test_mag",
|
||||
"summary": "dikjhgasdpas dsaü",
|
||||
"content": "dikjhgasdpas dsaü",
|
||||
"to": ["https://lemmy-test/c/test_mag"]
|
||||
}
|
|
@ -2,7 +2,10 @@ use crate::{
|
|||
activities::{generate_activity_id, send_lemmy_activity, verify_person_in_community},
|
||||
insert_received_activity,
|
||||
objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson},
|
||||
protocol::{activities::community::report::Report, InCommunity},
|
||||
protocol::{
|
||||
activities::community::report::{Report, ReportObject},
|
||||
InCommunity,
|
||||
},
|
||||
PostOrComment,
|
||||
};
|
||||
use activitypub_federation::{
|
||||
|
@ -45,8 +48,9 @@ impl Report {
|
|||
let report = Report {
|
||||
actor: actor.id().into(),
|
||||
to: [community.id().into()],
|
||||
object: object_id.clone(),
|
||||
summary: reason,
|
||||
object: ReportObject::Lemmy(object_id.clone()),
|
||||
summary: Some(reason),
|
||||
content: None,
|
||||
kind,
|
||||
id: id.clone(),
|
||||
audience: Some(community.id().into()),
|
||||
|
@ -97,6 +101,7 @@ impl ActivityHandler for Report {
|
|||
#[tracing::instrument(skip_all)]
|
||||
async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
|
||||
let actor = self.actor.dereference(context).await?;
|
||||
let reason = self.reason()?;
|
||||
match self.object.dereference(context).await? {
|
||||
PostOrComment::Post(post) => {
|
||||
let report_form = PostReportForm {
|
||||
|
@ -104,7 +109,7 @@ impl ActivityHandler for Report {
|
|||
post_id: post.id,
|
||||
original_post_name: post.name.clone(),
|
||||
original_post_url: post.url.clone(),
|
||||
reason: self.summary.clone(),
|
||||
reason,
|
||||
original_post_body: post.body.clone(),
|
||||
};
|
||||
PostReport::report(&mut context.pool(), &report_form).await?;
|
||||
|
@ -114,7 +119,7 @@ impl ActivityHandler for Report {
|
|||
creator_id: actor.id,
|
||||
comment_id: comment.id,
|
||||
original_comment_text: comment.content.clone(),
|
||||
reason: self.summary.clone(),
|
||||
reason,
|
||||
};
|
||||
CommentReport::report(&mut context.pool(), &report_form).await?;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use activitypub_federation::{
|
|||
protocol::helpers::deserialize_one,
|
||||
};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_utils::error::LemmyError;
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
|
@ -21,14 +21,54 @@ pub struct Report {
|
|||
pub(crate) actor: ObjectId<ApubPerson>,
|
||||
#[serde(deserialize_with = "deserialize_one")]
|
||||
pub(crate) to: [ObjectId<ApubCommunity>; 1],
|
||||
pub(crate) object: ObjectId<PostOrComment>,
|
||||
pub(crate) summary: String,
|
||||
pub(crate) object: ReportObject,
|
||||
/// Report reason as sent by Lemmy
|
||||
pub(crate) summary: Option<String>,
|
||||
/// Report reason as sent by Mastodon
|
||||
pub(crate) content: Option<String>,
|
||||
#[serde(rename = "type")]
|
||||
pub(crate) kind: FlagType,
|
||||
pub(crate) id: Url,
|
||||
pub(crate) audience: Option<ObjectId<ApubCommunity>>,
|
||||
}
|
||||
|
||||
impl Report {
|
||||
pub fn reason(&self) -> LemmyResult<String> {
|
||||
self
|
||||
.summary
|
||||
.clone()
|
||||
.or(self.content.clone())
|
||||
.ok_or(LemmyErrorType::CouldntFindObject.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub(crate) enum ReportObject {
|
||||
Lemmy(ObjectId<PostOrComment>),
|
||||
/// Mastodon sends an array containing user id and one or more post ids
|
||||
Mastodon(Vec<Url>),
|
||||
}
|
||||
|
||||
impl ReportObject {
|
||||
pub async fn dereference(self, context: &Data<LemmyContext>) -> LemmyResult<PostOrComment> {
|
||||
match self {
|
||||
ReportObject::Lemmy(l) => l.dereference(context).await,
|
||||
ReportObject::Mastodon(objects) => {
|
||||
for o in objects {
|
||||
// Find the first reported item which can be dereferenced as post or comment (Lemmy can
|
||||
// only handle one item per report).
|
||||
let deref = ObjectId::from(o).dereference(context).await;
|
||||
if deref.is_ok() {
|
||||
return deref;
|
||||
}
|
||||
}
|
||||
Err(LemmyErrorType::CouldntFindObject.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InCommunity for Report {
|
||||
async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
|
||||
|
|
|
@ -18,10 +18,10 @@ pub enum CreateOrUpdateType {
|
|||
mod tests {
|
||||
use crate::protocol::{
|
||||
activities::{
|
||||
community::announce::AnnounceActivity,
|
||||
community::{announce::AnnounceActivity, report::Report},
|
||||
create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage},
|
||||
deletion::delete::Delete,
|
||||
following::{follow::Follow, undo_follow::UndoFollow},
|
||||
following::{accept::AcceptFollow, follow::Follow, undo_follow::UndoFollow},
|
||||
voting::{undo_vote::UndoVote, vote::Vote},
|
||||
},
|
||||
tests::test_json,
|
||||
|
@ -50,6 +50,7 @@ mod tests {
|
|||
test_json::<UndoFollow>("assets/mastodon/activities/undo_follow.json")?;
|
||||
test_json::<Vote>("assets/mastodon/activities/like_page.json")?;
|
||||
test_json::<UndoVote>("assets/mastodon/activities/undo_like_page.json")?;
|
||||
test_json::<Report>("assets/mastodon/activities/flag.json")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -88,4 +89,11 @@ mod tests {
|
|||
test_json::<AnnounceActivity>("assets/peertube/activities/announce_video.json")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_mbin_activities() -> LemmyResult<()> {
|
||||
test_json::<AcceptFollow>("assets/mbin/activities/accept.json")?;
|
||||
test_json::<Report>("assets/mbin/activities/flag.json")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue