transmogrifier: more robustly handle dereferencing pointer URIs
authorWilliam Pitcock <nenolod@dereferenced.org>
Thu, 27 Sep 2018 07:14:15 +0000 (07:14 +0000)
committerHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Thu, 27 Sep 2018 18:00:48 +0000 (20:00 +0200)
lib/pleroma/web/activity_pub/transmogrifier.ex
test/fixtures/httpoison_mock/http___mastodon.example.org_users_admin_status_1234.json [new file with mode: 0644]
test/fixtures/kroeg-announce-with-inline-actor.json
test/support/httpoison_mock.ex
test/web/activity_pub/transmogrifier_test.exs

index 29d7b642b8e5b9ec438646784fa8dfccd4909e4c..611c0e623bb976bc26a0be0c4cb41422ffa65a55 100644 (file)
@@ -114,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           ""
       end
 
-    case ActivityPub.fetch_object_from_id(in_reply_to_id) do
+    case fetch_obj_helper(in_reply_to_id) do
       {:ok, replied_object} ->
         with %Activity{} = activity <-
                Activity.get_create_activity_by_object_ap_id(replied_object.data["id"]) do
@@ -323,7 +323,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Accept", "object" => follow_object, "actor" => actor, "id" => id} = data
       ) do
-    with %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
+    with actor <- get_actor(data),
+         %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
          {:ok, follow_activity} <- get_follow_activity(follow_object, followed),
          %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
          {:ok, activity} <-
@@ -347,7 +348,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Reject", "object" => follow_object, "actor" => actor, "id" => id} = data
       ) do
-    with %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
+    with actor <- get_actor(data),
+         %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
          {:ok, follow_activity} <- get_follow_activity(follow_object, followed),
          %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
          {:ok, activity} <-
@@ -367,11 +369,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = _data
+        %{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data
       ) do
-    with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
-         {:ok, object} <-
-           get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+    with actor <- get_actor(data),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
          {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
       {:ok, activity}
     else
@@ -380,11 +382,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = _data
+        %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
       ) do
-    with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
-         {:ok, object} <-
-           get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+    with actor <- get_actor(data),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
          {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do
       {:ok, activity}
     else
@@ -428,13 +430,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   # TODO: Make secure.
   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 %User{} = _actor <- User.get_or_fetch_by_ap_id(actor),
-         {:ok, object} <-
-           get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+    with actor <- get_actor(data),
+         %User{} = _actor <- User.get_or_fetch_by_ap_id(actor),
+         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
          {:ok, activity} <- ActivityPub.delete(object, false) do
       {:ok, activity}
     else
@@ -448,11 +450,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Announce", "object" => object_id},
           "actor" => actor,
           "id" => id
-        } = _data
+        } = data
       ) do
-    with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
-         {:ok, object} <-
-           get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+    with actor <- get_actor(data),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
          {:ok, activity, _} <- ActivityPub.unannounce(actor, object, id, false) do
       {:ok, activity}
     else
@@ -521,11 +523,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Like", "object" => object_id},
           "actor" => actor,
           "id" => id
-        } = _data
+        } = data
       ) do
-    with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
-         {:ok, object} <-
-           get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+    with actor <- get_actor(data),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
          {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
       {:ok, activity}
     else
@@ -535,6 +537,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def handle_incoming(_), do: :error
 
+  def fetch_obj_helper(id) when is_bitstring(id), do: ActivityPub.fetch_object_from_id(id)
+  def fetch_obj_helper(obj) when is_map(obj), do: ActivityPub.fetch_object_from_id(obj["id"])
+
   def get_obj_helper(id) do
     if object = Object.normalize(id), do: {:ok, object}, else: nil
   end
@@ -630,7 +635,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def maybe_fix_object_url(data) do
     if is_binary(data["object"]) and not String.starts_with?(data["object"], "http") do
-      case ActivityPub.fetch_object_from_id(data["object"]) do
+      case fetch_obj_helper(data["object"]) do
         {:ok, relative_object} ->
           if relative_object.data["external_url"] do
             _data =
diff --git a/test/fixtures/httpoison_mock/http___mastodon.example.org_users_admin_status_1234.json b/test/fixtures/httpoison_mock/http___mastodon.example.org_users_admin_status_1234.json
new file mode 100644 (file)
index 0000000..5c7c9c6
--- /dev/null
@@ -0,0 +1,55 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://w3id.org/security/v1",
+        {
+            "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+            "sensitive": "as:sensitive",
+            "movedTo": {
+                "@id": "as:movedTo",
+                "@type": "@id"
+            },
+            "Hashtag": "as:Hashtag",
+            "ostatus": "http://ostatus.org#",
+            "atomUri": "ostatus:atomUri",
+            "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+            "conversation": "ostatus:conversation",
+            "toot": "http://joinmastodon.org/ns#",
+            "Emoji": "toot:Emoji",
+            "focalPoint": {
+                "@container": "@list",
+                "@id": "toot:focalPoint"
+            },
+            "featured": {
+                "@id": "toot:featured",
+                "@type": "@id"
+            },
+            "schema": "http://schema.org#",
+            "PropertyValue": "schema:PropertyValue",
+            "value": "schema:value"
+        }
+    ],
+    "id": "http://mastodon.example.org/users/admin/statuses/100787282858396771",
+    "type": "Note",
+    "summary": null,
+    "inReplyTo": null,
+    "published": "2018-09-25T16:11:29Z",
+    "url": "https://mastodon.example.org/@admin/100787282858396771",
+    "attributedTo": "http://mastodon.example.org/users/admin",
+    "to": [
+        "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "cc": [
+        "http://mastodon.example.org/users/admin/followers"
+    ],
+    "sensitive": false,
+    "atomUri": "http://mastodon.example.org/users/admin/statuses/100787282858396771",
+    "inReplyToAtomUri": null,
+    "conversation": "tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation",
+    "content": "<p>the name&apos;s jond (jeans bond)</p>",
+    "contentMap": {
+        "en": "<p>the name&apos;s jond (jeans bond)</p>"
+    },
+    "attachment": [],
+    "tag": []
+}
index a2a7e2396a24a27eba0bd639eacd0665fc71e078..7bd6e81991e42cce072b86f885d94dcb4015b4c6 100644 (file)
@@ -1 +1 @@
-{"@context":["https://www.w3.org/ns/activitystreams","https://puckipedia.com/-/context"],"actor":{"endpoints":"https://puckipedia.com/#endpoints","followers":"https://puckipedia.com/followers","following":"https://puckipedia.com/following","icon":{"mediaType":"image/png","type":"Image","url":"https://puckipedia.com/images/avatar.png"},"id":"https://puckipedia.com/","inbox":"https://puckipedia.com/inbox","kroeg:blocks":{"id":"https://puckipedia.com/blocks"},"liked":"https://puckipedia.com/liked","manuallyApprovesFollowers":false,"name":"HACKER TEEN PUCKIPEDIA 👩‍💻","outbox":"https://puckipedia.com/outbox","preferredUsername":"puckipedia","publicKey":{"id":"https://puckipedia.com/#key","owner":"https://puckipedia.com/","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----","type":[]},"summary":"<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>","type":"Person","updated":"2017-12-19T16:56:29.7576707+00:00"},"cc":"https://mastodon.social/users/revenant","id":"https://puckipedia.com/cc56a9658e","object":{"as:sensitive":false,"attributedTo":{"endpoints":{"sharedInbox":"https://mastodon.social/inbox","type":[]},"followers":"https://mastodon.social/users/revenant/followers","following":"https://mastodon.social/users/revenant/following","icon":{"mediaType":"image/png","type":"Image","url":"https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"},"id":"https://mastodon.social/users/revenant","inbox":"https://mastodon.social/users/revenant/inbox","manuallyApprovesFollowers":{"@value":"False","type":"xsd:boolean"},"name":"","outbox":"https://mastodon.social/users/revenant/outbox","preferredUsername":"revenant","publicKey":{"id":"https://mastodon.social/users/revenant#main-key","owner":"https://mastodon.social/users/revenant","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n","type":[]},"summary":"<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>","type":"Person","url":"https://mastodon.social/@revenant"},"cc":"https://mastodon.social/users/revenant/followers","content":"<p>the name&apos;s jond (jeans bond)</p>","contentMap":{"en":"<p>the name&apos;s jond (jeans bond)</p>"},"conversation":"tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation","id":"https://mastodon.social/users/revenant/statuses/100787282858396771","ostatus:atomUri":"https://mastodon.social/users/revenant/statuses/100787282858396771","published":"2018-09-25T16:11:29Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"https://mastodon.social/@revenant/100787282858396771"},"to":["https://www.w3.org/ns/activitystreams#Public","https://puckipedia.com/followers"],"type":"Announce"}
\ No newline at end of file
+{"@context":["https://www.w3.org/ns/activitystreams","https://puckipedia.com/-/context"],"actor":{"endpoints":"https://puckipedia.com/#endpoints","followers":"https://puckipedia.com/followers","following":"https://puckipedia.com/following","icon":{"mediaType":"image/png","type":"Image","url":"https://puckipedia.com/images/avatar.png"},"id":"https://puckipedia.com/","inbox":"https://puckipedia.com/inbox","kroeg:blocks":{"id":"https://puckipedia.com/blocks"},"liked":"https://puckipedia.com/liked","manuallyApprovesFollowers":false,"name":"HACKER TEEN PUCKIPEDIA 👩‍💻","outbox":"https://puckipedia.com/outbox","preferredUsername":"puckipedia","publicKey":{"id":"https://puckipedia.com/#key","owner":"https://puckipedia.com/","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----","type":[]},"summary":"<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>","type":"Person","updated":"2017-12-19T16:56:29.7576707+00:00"},"cc":"http://mastodon.example.org/users/admin","id":"https://puckipedia.com/cc56a9658e","object":{"as:sensitive":false,"attributedTo":{"endpoints":{"sharedInbox":"https://mastodon.social/inbox","type":[]},"followers":"http://mastodon.example.org/users/admin/followers","following":"http://mastodon.example.org/users/admin/following","icon":{"mediaType":"image/png","type":"Image","url":"https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"},"id":"http://mastodon.example.org/users/admin","inbox":"http://mastodon.example.org/users/admin/inbox","manuallyApprovesFollowers":{"@value":"False","type":"xsd:boolean"},"name":"","outbox":"http://mastodon.example.org/users/admin/outbox","preferredUsername":"revenant","publicKey":{"id":"http://mastodon.example.org/users/admin#main-key","owner":"http://mastodon.example.org/users/admin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n","type":[]},"summary":"<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>","type":"Person","url":"https://mastodon.social/@revenant"},"cc":"http://mastodon.example.org/users/admin/followers","content":"<p>the name&apos;s jond (jeans bond)</p>","contentMap":{"en":"<p>the name&apos;s jond (jeans bond)</p>"},"conversation":"tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation","id":"http://mastodon.example.org/users/admin/statuses/100787282858396771","ostatus:atomUri":"http://mastodon.example.org/users/admin/statuses/100787282858396771","published":"2018-09-25T16:11:29Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"https://mastodon.social/@revenant/100787282858396771"},"to":["https://www.w3.org/ns/activitystreams#Public","https://puckipedia.com/followers"],"type":"Announce"}
index 7057f30fb5e20b148799b6dce730e77bbefedf3d..d8b79abef9e2db524c53e922e7aefb51eb9a4098 100644 (file)
@@ -404,6 +404,17 @@ defmodule HTTPoisonMock do
      }}
   end
 
+  def get("http://mastodon.example.org/users/admin/statuses/100787282858396771", _, _) do
+    {:ok,
+     %Response{
+       status_code: 200,
+       body:
+         File.read!(
+           "test/fixtures/httpoison_mock/http___mastodon.example.org_users_admin_status_1234.json"
+         )
+     }}
+  end
+
   def get(
         "https://pawoo.net/.well-known/webfinger",
         [Accept: "application/xrd+xml,application/jrd+json"],
index 7b3c05caa187d52450b4efe69e9e524a63f5b31a..6a6f2a44cce24dea66d4dc43e9550d630f46403a 100644 (file)
@@ -121,15 +121,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
                "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
     end
 
-    # Broken ;/
-    #
-    #    test "it works for incoming announces with actor being inlined (kroeg)" do
-    #      data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
-    #
-    #      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-    #
-    #      assert data["object"]["actor"] == "https://puckipedia.com/"
-    #    end
+    test "it works for incoming announces with actor being inlined (kroeg)" do
+      data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+      assert data["actor"] == "https://puckipedia.com/"
+    end
 
     test "it works for incoming notices with tag not being an array (kroeg)" do
       data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()