From 90d516d42bd3d29e71e364535dd4208f8a54992a Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 15 Oct 2019 16:52:41 +0200 Subject: [PATCH 1/5] Store status data inside flag activity --- lib/pleroma/web/activity_pub/utils.ex | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4ef479f96..57982eb4a 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -609,9 +609,33 @@ def make_flag_data(_, _), do: %{} defp build_flag_object(%{account: account, statuses: statuses} = _) do [account.ap_id] ++ Enum.map(statuses || [], fn - %Activity{} = act -> act.data["id"] - act when is_map(act) -> act["id"] - act when is_binary(act) -> act + %Activity{} = act -> + obj = Object.get_by_ap_id(act.data["object"]) + + %{ + "type" => "Note", + "id" => act.data["id"], + "content" => obj.data["content"] + } + + act when is_map(act) -> + obj = Object.get_by_ap_id(act["object"]) + + %{ + "type" => "Note", + "id" => act["id"], + "content" => obj.data["content"] + } + + act + when is_binary(act) -> + activity = Activity.get_by_ap_id_with_object(act) + + %{ + "type" => "Note", + "id" => activity.data["id"], + "content" => activity.data["object"]["content"] + } end) end From b08b1d5d91968fbe94e20897ee3529216dd50a0a Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 23 Oct 2019 21:27:22 +0200 Subject: [PATCH 2/5] Store status data inside Flag activity --- lib/pleroma/web/activity_pub/utils.ex | 43 ++++++++----------- lib/pleroma/web/admin_api/report.ex | 4 +- test/web/activity_pub/activity_pub_test.exs | 13 +++++- test/web/activity_pub/transmogrifier_test.exs | 13 +++++- test/web/activity_pub/utils_test.exs | 11 ++++- test/web/common_api/common_api_test.exs | 11 ++++- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 57982eb4a..c58ee7482 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.Endpoint alias Pleroma.Web.Router.Helpers @@ -608,34 +609,24 @@ def make_flag_data(_, _), do: %{} defp build_flag_object(%{account: account, statuses: statuses} = _) do [account.ap_id] ++ - Enum.map(statuses || [], fn - %Activity{} = act -> - obj = Object.get_by_ap_id(act.data["object"]) + Enum.map(statuses || [], fn act -> + id = + case act do + %Activity{} = act -> act.data["id"] + act when is_map(act) -> act["id"] + act when is_binary(act) -> act + end - %{ - "type" => "Note", - "id" => act.data["id"], - "content" => obj.data["content"] - } + activity = Activity.get_by_ap_id_with_object(id) + actor = User.get_by_ap_id(activity.object.data["actor"]) - act when is_map(act) -> - obj = Object.get_by_ap_id(act["object"]) - - %{ - "type" => "Note", - "id" => act["id"], - "content" => obj.data["content"] - } - - act - when is_binary(act) -> - activity = Activity.get_by_ap_id_with_object(act) - - %{ - "type" => "Note", - "id" => activity.data["id"], - "content" => activity.data["object"]["content"] - } + %{ + "type" => "Note", + "id" => activity.data["id"], + "content" => activity.object.data["content"], + "published" => activity.object.data["published"], + "actor" => AccountView.render("show.json", %{user: actor}) + } end) end diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index c751dc2be..ccd56e15e 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -13,8 +13,8 @@ def extract_report_info( account = User.get_cached_by_ap_id(account_ap_id) statuses = - Enum.map(status_ap_ids, fn ap_id -> - Activity.get_by_ap_id_with_object(ap_id) + Enum.map(status_ap_ids, fn act -> + Activity.get_by_ap_id_with_object(act["id"]) end) %{report: report, user: user, account: account, statuses: statuses} diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 3a5a2f984..cbd81b698 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -1265,6 +1266,8 @@ test "it can create a Flag activity" do target_ap_id = target_account.ap_id activity_ap_id = activity.data["id"] + activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id) + assert {:ok, activity} = ActivityPub.flag(%{ actor: reporter, @@ -1274,13 +1277,21 @@ test "it can create a Flag activity" do content: content }) + note_obj = %{ + "type" => "Note", + "id" => activity_ap_id, + "content" => content, + "published" => activity_with_object.object.data["published"], + "actor" => AccountView.render("show.json", %{user: target_account}) + } + assert %Activity{ actor: ^reporter_ap_id, data: %{ "type" => "Flag", "content" => ^content, "context" => ^context, - "object" => [^target_ap_id, ^activity_ap_id] + "object" => [^target_ap_id, ^note_obj] } } = activity end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 6c35a6f4d..82389b344 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI alias Pleroma.Web.OStatus alias Pleroma.Web.Websub.WebsubClientSubscription @@ -1093,10 +1094,18 @@ test "it accepts Flag activities" do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) object = Object.normalize(activity) + note_obj = %{ + "type" => "Note", + "id" => activity.data["id"], + "content" => "test post", + "published" => object.data["published"], + "actor" => AccountView.render("show.json", %{user: user}) + } + message = %{ "@context" => "https://www.w3.org/ns/activitystreams", "cc" => [user.ap_id], - "object" => [user.ap_id, object.data["id"]], + "object" => [user.ap_id, activity], "type" => "Flag", "content" => "blocked AND reported!!!", "actor" => other_user.ap_id @@ -1104,7 +1113,7 @@ test "it accepts Flag activities" do assert {:ok, activity} = Transmogrifier.handle_incoming(message) - assert activity.data["object"] == [user.ap_id, object.data["id"]] + assert activity.data["object"] == [user.ap_id, note_obj] assert activity.data["content"] == "blocked AND reported!!!" assert activity.data["actor"] == other_user.ap_id assert activity.data["cc"] == [user.ap_id] diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index c57ea7eb9..4475d06d2 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -581,11 +582,19 @@ test "returns map with Flag object" do %{} ) + note_obj = %{ + "type" => "Note", + "id" => activity_ap_id, + "content" => content, + "published" => activity.object.data["published"], + "actor" => AccountView.render("show.json", %{user: target_account}) + } + assert %{ "type" => "Flag", "content" => ^content, "context" => ^context, - "object" => [^target_ap_id, ^activity_ap_id], + "object" => [^target_ap_id, ^note_obj], "state" => "open" } = res end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 83df44c36..709aa4dbe 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.CommonAPITest do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -385,6 +386,14 @@ test "creates a report" do "status_ids" => [activity.id] } + note_obj = %{ + "type" => "Note", + "id" => activity_ap_id, + "content" => "foobar", + "published" => activity.object.data["published"], + "actor" => AccountView.render("show.json", %{user: target_user}) + } + assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data) assert %Activity{ @@ -392,7 +401,7 @@ test "creates a report" do data: %{ "type" => "Flag", "content" => ^comment, - "object" => [^target_ap_id, ^activity_ap_id], + "object" => [^target_ap_id, ^note_obj], "state" => "open" } } = flag_activity From 8eff05d4c62c4d3300fee173cad84f75a0aafb4d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 27 Oct 2019 16:05:32 +0300 Subject: [PATCH 3/5] Strip status data from Flag (when federating or closing/resolving report) --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 3 +- lib/pleroma/web/activity_pub/utils.ex | 23 ++++ test/web/activity_pub/activity_pub_test.exs | 122 +++++++++++++------ test/web/common_api/common_api_test.exs | 5 + 5 files changed, 119 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3ccfa4ea..4744567d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF (Simple Policy): Also use `:accept`/`:reject` on the actors rather than only their activities - OStatus: Extract RSS functionality - Mastodon API: Add `pleroma.direct_conversation_id` to the status endpoint (`GET /api/v1/statuses/:id`) +- Store status data inside Flag activity ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1d34c4d7e..4cdf4876e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -491,7 +491,8 @@ def flag( with flag_data <- make_flag_data(params, additional), {:ok, activity} <- insert(flag_data, local), - :ok <- maybe_federate(activity) do + {:ok, stripped_activity} <- strip_report_status_data(activity), + :ok <- maybe_federate(stripped_activity) do Enum.each(User.all_superusers(), fn superuser -> superuser |> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c58ee7482..520cc1b0c 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -22,6 +22,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Pleroma.Constants @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer", "Audio"] + @strip_status_report_states ~w(closed resolved) @supported_report_states ~w(open closed resolved) @valid_visibilities ~w(public unlisted private direct) @@ -673,6 +674,20 @@ def fetch_ordered_collection(from, pages_left, acc \\ []) do #### Report-related helpers + def update_report_state(%Activity{} = activity, state) + when state in @strip_status_report_states do + {:ok, stripped_activity} = strip_report_status_data(activity) + + new_data = + activity.data + |> Map.put("state", state) + |> Map.put("object", stripped_activity.data["object"]) + + activity + |> Changeset.change(data: new_data) + |> Repo.update() + end + def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do new_data = Map.put(activity.data, "state", state) @@ -683,6 +698,14 @@ def update_report_state(%Activity{} = activity, state) when state in @supported_ def update_report_state(_, _), do: {:error, "Unsupported state"} + def strip_report_status_data(activity) do + [actor | reported_activities] = activity.data["object"] + stripped_activities = Enum.map(reported_activities, & &1["id"]) + new_data = put_in(activity.data, ["object"], [actor | stripped_activities]) + + {:ok, %{activity | data: new_data}} + end + def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do [to, cc, recipients] = activity diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index cbd81b698..ddc6493c0 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1255,45 +1255,99 @@ test "returned pinned statuses" do assert 3 = length(activities) end - test "it can create a Flag activity" do - reporter = insert(:user) - target_account = insert(:user) - {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"}) - context = Utils.generate_context_id() - content = "foobar" + describe "flag/1" do + setup do + reporter = insert(:user) + target_account = insert(:user) + content = "foobar" + {:ok, activity} = CommonAPI.post(target_account, %{"status" => content}) + context = Utils.generate_context_id() - reporter_ap_id = reporter.ap_id - target_ap_id = target_account.ap_id - activity_ap_id = activity.data["id"] + reporter_ap_id = reporter.ap_id + target_ap_id = target_account.ap_id + activity_ap_id = activity.data["id"] - activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id) + activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id) - assert {:ok, activity} = - ActivityPub.flag(%{ - actor: reporter, - context: context, - account: target_account, - statuses: [activity], - content: content - }) + {:ok, + %{ + reporter: reporter, + context: context, + target_account: target_account, + reported_activity: activity, + content: content, + activity_ap_id: activity_ap_id, + activity_with_object: activity_with_object, + reporter_ap_id: reporter_ap_id, + target_ap_id: target_ap_id + }} + end - note_obj = %{ - "type" => "Note", - "id" => activity_ap_id, - "content" => content, - "published" => activity_with_object.object.data["published"], - "actor" => AccountView.render("show.json", %{user: target_account}) - } + test "it can create a Flag activity", + %{ + reporter: reporter, + context: context, + target_account: target_account, + reported_activity: reported_activity, + content: content, + activity_ap_id: activity_ap_id, + activity_with_object: activity_with_object, + reporter_ap_id: reporter_ap_id, + target_ap_id: target_ap_id + } do + assert {:ok, activity} = + ActivityPub.flag(%{ + actor: reporter, + context: context, + account: target_account, + statuses: [reported_activity], + content: content + }) - assert %Activity{ - actor: ^reporter_ap_id, - data: %{ - "type" => "Flag", - "content" => ^content, - "context" => ^context, - "object" => [^target_ap_id, ^note_obj] - } - } = activity + note_obj = %{ + "type" => "Note", + "id" => activity_ap_id, + "content" => content, + "published" => activity_with_object.object.data["published"], + "actor" => AccountView.render("show.json", %{user: target_account}) + } + + assert %Activity{ + actor: ^reporter_ap_id, + data: %{ + "type" => "Flag", + "content" => ^content, + "context" => ^context, + "object" => [^target_ap_id, ^note_obj] + } + } = activity + end + + test_with_mock "strips status data from Flag, before federating it", + %{ + reporter: reporter, + context: context, + target_account: target_account, + reported_activity: reported_activity, + content: content + }, + Utils, + [:passthrough], + [] do + {:ok, activity} = + ActivityPub.flag(%{ + actor: reporter, + context: context, + account: target_account, + statuses: [reported_activity], + content: content + }) + + new_data = + put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]]) + + assert_called(Utils.maybe_federate(%{activity | data: new_data})) + end end test "fetch_activities/2 returns activities addressed to a list " do diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 709aa4dbe..d69ed38a7 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -421,6 +421,11 @@ test "updates report state" do {:ok, report} = CommonAPI.update_report_state(report_id, "resolved") assert report.data["state"] == "resolved" + + [reported_user, activity_id] = report.data["object"] + + assert reported_user == target_user.ap_id + assert activity_id == activity.data["id"] end test "does not update report state when state is unsupported" do From 8282b6ac3d977e2e427c42ef3669d547170cc27d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 27 Oct 2019 16:17:37 +0300 Subject: [PATCH 4/5] Make sure incoming flags are updated with status data --- test/web/activity_pub/transmogrifier_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 1069ade02..4df3024a6 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1102,7 +1102,7 @@ test "it accepts Flag activities" do message = %{ "@context" => "https://www.w3.org/ns/activitystreams", "cc" => [user.ap_id], - "object" => [user.ap_id, activity], + "object" => [user.ap_id, activity.data["id"]], "type" => "Flag", "content" => "blocked AND reported!!!", "actor" => other_user.ap_id From d56bc622755ea0a858bf086bc1f525c1752e4db8 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 27 Oct 2019 16:33:58 +0300 Subject: [PATCH 5/5] Fix report parsing --- lib/pleroma/web/admin_api/report.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index ccd56e15e..9c3468570 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -13,8 +13,9 @@ def extract_report_info( account = User.get_cached_by_ap_id(account_ap_id) statuses = - Enum.map(status_ap_ids, fn act -> - Activity.get_by_ap_id_with_object(act["id"]) + Enum.map(status_ap_ids, fn + act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"]) + act when is_binary(act) -> Activity.get_by_ap_id_with_object(act) end) %{report: report, user: user, account: account, statuses: statuses}