ActivityPub: Fix deletes being exempt from MRF
authorrinpatch <rinpatch@sdf.org>
Wed, 4 Dec 2019 23:50:38 +0000 (02:50 +0300)
committerrinpatch <rinpatch@sdf.org>
Thu, 5 Dec 2019 18:45:57 +0000 (21:45 +0300)
Closes #1461

CHANGELOG.md
lib/pleroma/activity.ex
lib/pleroma/activity/queries.ex
lib/pleroma/object.ex
lib/pleroma/web/activity_pub/activity_pub.ex
test/web/activity_pub/activity_pub_controller_test.exs
test/web/activity_pub/activity_pub_test.exs

index a06ea211eb9dcf6b401c799c5357d3b8d04a1093..3ec34f45205f619abebfdc31615c80aff4380f5d 100644 (file)
@@ -78,6 +78,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Fixed
 - Report emails now include functional links to profiles of remote user accounts
 - Not being able to log in to some third-party apps when logged in to MastoFE
+- MRF: `Delete` activities being exempt from MRF policies
 <details>
   <summary>API Changes</summary>
 
index f180c1e3311021a92ea4e2bd40dd53e877d2fa6c..480b261cfdae0e2615e612b675d3022aaef43d7e 100644 (file)
@@ -241,9 +241,10 @@ defmodule Pleroma.Activity do
   def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id)
   def normalize(_), do: nil
 
-  def delete_by_ap_id(id) when is_binary(id) do
+  def delete_all_by_object_ap_id(id) when is_binary(id) do
     id
     |> Queries.by_object_id()
+    |> Queries.exclude_type("Delete")
     |> select([u], u)
     |> Repo.delete_all()
     |> elem(1)
@@ -255,7 +256,7 @@ defmodule Pleroma.Activity do
     |> purge_web_resp_cache()
   end
 
-  def delete_by_ap_id(_), do: nil
+  def delete_all_by_object_ap_id(_), do: nil
 
   defp purge_web_resp_cache(%Activity{} = activity) do
     %{path: path} = URI.parse(activity.data["id"])
index 949f010a81f840368fa8cf41a1f39297b8132104..26bc1099daea092b78ae7b6e5ad9c0c561608183 100644 (file)
@@ -64,4 +64,12 @@ defmodule Pleroma.Activity.Queries do
       where: fragment("(?)->>'type' = ?", activity.data, ^activity_type)
     )
   end
+
+  @spec exclude_type(query, String.t()) :: query
+  def exclude_type(query \\ Activity, activity_type) do
+    from(
+      activity in query,
+      where: fragment("(?)->>'type' != ?", activity.data, ^activity_type)
+    )
+  end
 end
index b4ed3a9b2d1ba7b0004e213f0924009cb081bc8c..ff0e592418a4c9b9d1a3e5f5a3f1cabeeaa8a718 100644 (file)
@@ -147,7 +147,7 @@ defmodule Pleroma.Object do
 
   def delete(%Object{data: %{"id" => id}} = object) do
     with {:ok, _obj} = swap_object_with_tombstone(object),
-         deleted_activity = Activity.delete_by_ap_id(id),
+         deleted_activity = Activity.delete_all_by_object_ap_id(id),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
          {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
       {:ok, object, deleted_activity}
index d6a425d8bd0f6628e4a1ec606402806c4fea89d3..c8160b0cf9e9e0609ccfc141b2baa6acab78b832 100644 (file)
@@ -456,17 +456,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     user = User.get_cached_by_ap_id(actor)
     to = (object.data["to"] || []) ++ (object.data["cc"] || [])
 
-    with {:ok, object, activity} <- Object.delete(object),
+    with create_activity <- Activity.get_create_by_object_ap_id(id),
          data <-
            %{
              "type" => "Delete",
              "actor" => actor,
              "object" => id,
              "to" => to,
-             "deleted_activity_id" => activity && activity.id
+             "deleted_activity_id" => create_activity && create_activity.id
            }
            |> maybe_put("id", activity_id),
          {:ok, activity} <- insert(data, local, false),
+         {:ok, object, _create_activity} <- Object.delete(object),
          stream_out_participations(object, user),
          _ <- decrease_replies_count_if_reply(object),
          {:ok, _actor} <- decrease_note_count_if_public(user, object),
index 1aa73d75cf675efee5dfd1df83028840b92324b5..ba2ce1dd9157e5ea3ac854398a11208968969a1a 100644 (file)
@@ -298,7 +298,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       assert json_response(conn1, :ok)
       assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
 
-      Activity.delete_by_ap_id(activity.object.data["id"])
+      Activity.delete_all_by_object_ap_id(activity.object.data["id"])
 
       conn2 =
         conn
index 2677b9e36bbd48b1a700a2dc9f5811f997dc237a..23dffb1509db126094d148c3fd8aabd9afd4ae8a 100644 (file)
@@ -1256,6 +1256,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
       assert object.data["repliesCount"] == 0
     end
+
+    test "it passes delete activity through MRF before deleting the object" do
+      rewrite_policy = Pleroma.Config.get([:instance, :rewrite_policy])
+      Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy)
+
+      on_exit(fn -> Pleroma.Config.put([:instance, :rewrite_policy], rewrite_policy) end)
+
+      note = insert(:note_activity)
+      object = Object.normalize(note)
+
+      {:error, {:reject, _}} = ActivityPub.delete(object)
+
+      assert Activity.get_by_id(note.id)
+      assert Repo.get(Object, object.id).data["type"] == object.data["type"]
+    end
   end
 
   describe "timeline post-processing" do