From a88734a0a22810bcc47c17fc9120ef7881d670d8 Mon Sep 17 00:00:00 2001
From: lain <lain@soykaf.club>
Date: Wed, 29 Apr 2020 14:25:33 +0200
Subject: [PATCH] Transmogrifier: Fetch missing actors for chatmessages.

---
 .../web/activity_pub/object_validator.ex      |  9 ++++-
 .../create_chat_message_validator.ex          |  2 +
 .../web/activity_pub/transmogrifier.ex        |  8 ++--
 .../transmogrifier/chat_message_test.exs      | 40 ++++++++++++++++---
 4 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index bada3509d..50904ed59 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
 
   alias Pleroma.Object
   alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.ObjectValidators.Types
   alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@@ -67,8 +68,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
     |> Map.new(fn {key, val} -> {to_string(key), val} end)
   end
 
+  def fetch_actor(object) do
+    with {:ok, actor} <- Types.ObjectID.cast(object["actor"]) do
+      User.get_or_fetch_by_ap_id(actor)
+    end
+  end
+
   def fetch_actor_and_object(object) do
-    User.get_or_fetch_by_ap_id(object["actor"])
+    fetch_actor(object)
     Object.normalize(object["object"])
     :ok
   end
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex
index dfc91bf71..88e903182 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex
@@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator do
   alias Pleroma.Web.ActivityPub.ObjectValidators.Types
 
   import Ecto.Changeset
+  import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
 
   @primary_key false
 
@@ -42,6 +43,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator do
     cng
     |> validate_required([:id, :actor, :to, :type, :object])
     |> validate_inclusion(:type, ["Create"])
+    |> validate_actor_presence()
     |> validate_recipients_match(meta)
     |> validate_object_nonexistence()
   end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 3c2fe73a3..6dbd3f588 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -647,10 +647,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
         %{"type" => "Create", "object" => %{"type" => "ChatMessage"}} = data,
         _options
       ) do
-    case Pipeline.common_pipeline(data, local: false) do
-      {:ok, activity, _} ->
-        {:ok, activity}
-
+    with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
+         {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
+      {:ok, activity}
+    else
       e ->
         e
     end
diff --git a/test/web/activity_pub/transmogrifier/chat_message_test.exs b/test/web/activity_pub/transmogrifier/chat_message_test.exs
index c5600e84e..85644d787 100644
--- a/test/web/activity_pub/transmogrifier/chat_message_test.exs
+++ b/test/web/activity_pub/transmogrifier/chat_message_test.exs
@@ -26,8 +26,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
         data
         |> Map.put("object", object)
 
-      _author = insert(:user, ap_id: data["actor"], local: false)
-      _recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
+      _author =
+        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
+
+      _recipient =
+        insert(:user,
+          ap_id: List.first(data["to"]),
+          local: true,
+          last_refreshed_at: DateTime.utc_now()
+        )
 
       {:error, _} = Transmogrifier.handle_incoming(data)
     end
@@ -37,8 +44,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
         File.read!("test/fixtures/create-chat-message.json")
         |> Poison.decode!()
 
-      _author = insert(:user, ap_id: data["actor"], local: false)
-      _recipient = insert(:user, ap_id: List.first(data["to"]), local: false)
+      _author =
+        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
+
+      _recipient =
+        insert(:user,
+          ap_id: List.first(data["to"]),
+          local: false,
+          last_refreshed_at: DateTime.utc_now()
+        )
 
       {:error, _} = Transmogrifier.handle_incoming(data)
     end
@@ -59,12 +73,28 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
       refute Object.get_by_ap_id(data["object"]["id"])
     end
 
+    test "it fetches the actor if they aren't in our system" do
+      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+      data =
+        File.read!("test/fixtures/create-chat-message.json")
+        |> Poison.decode!()
+        |> Map.put("actor", "http://mastodon.example.org/users/admin")
+        |> put_in(["object", "actor"], "http://mastodon.example.org/users/admin")
+
+      _recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
+
+      {:ok, %Activity{} = _activity} = Transmogrifier.handle_incoming(data)
+    end
+
     test "it inserts it and creates a chat" do
       data =
         File.read!("test/fixtures/create-chat-message.json")
         |> Poison.decode!()
 
-      author = insert(:user, ap_id: data["actor"], local: false)
+      author =
+        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
+
       recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
 
       {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data)