activitypub: transmogrifier: make deletes secure
authorWilliam Pitcock <nenolod@dereferenced.org>
Sat, 17 Nov 2018 21:22:30 +0000 (21:22 +0000)
committerWilliam Pitcock <nenolod@dereferenced.org>
Sat, 17 Nov 2018 21:22:57 +0000 (21:22 +0000)
lib/pleroma/web/activity_pub/transmogrifier.ex
test/web/activity_pub/transmogrifier_test.exs

index 1f886839e9c152cb11edfb9888bd5ba7643f008a..5864855b0bb8a8f420ec90c2fa3adc00f4b621ec 100644 (file)
@@ -467,15 +467,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  # TODO: Make secure.
+  # TODO: We presently assume that any actor on the same origin domain as the object being
+  # deleted has the rights to delete that object.  A better way to validate whether or not
+  # the object should be deleted is to refetch the object URI, which should return either
+  # an error or a tombstone.  This would allow us to verify that a deletion actually took
+  # place.
   def handle_incoming(
-        %{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = data
+        %{"type" => "Delete", "object" => object_id, "actor" => _actor, "id" => _id} = data
       ) do
     object_id = Utils.get_ap_id(object_id)
 
     with actor <- get_actor(data),
-         %User{} = _actor <- User.get_or_fetch_by_ap_id(actor),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
          {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
+         :ok <- contain_origin(actor.ap_id, object.data),
          {:ok, activity} <- ActivityPub.delete(object, false) do
       {:ok, activity}
     else
index 9174d9b764f0d4886e62c5955ab3edc0acdd2927..829da0a6545d2938f8be23b8533ce666a228bf7e 100644 (file)
@@ -361,6 +361,26 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       refute Repo.get(Activity, activity.id)
     end
 
+    test "it fails for incoming deletes with spoofed origin" do
+      activity = insert(:note_activity)
+
+      data =
+        File.read!("test/fixtures/mastodon-delete.json")
+        |> Poison.decode!()
+
+      object =
+        data["object"]
+        |> Map.put("id", activity.data["object"]["id"])
+
+      data =
+        data
+        |> Map.put("object", object)
+
+      :error = Transmogrifier.handle_incoming(data)
+
+      assert Repo.get(Activity, activity.id)
+    end
+
     test "it works for incoming unannounces with an existing notice" do
       user = insert(:user)
       {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})