ObjectValidators: Add basic Announce validator.
authorlain <lain@soykaf.club>
Mon, 18 May 2020 14:45:11 +0000 (16:45 +0200)
committerlain <lain@soykaf.club>
Mon, 18 May 2020 14:45:11 +0000 (16:45 +0200)
lib/pleroma/web/activity_pub/builder.ex
lib/pleroma/web/activity_pub/object_validator.ex
lib/pleroma/web/activity_pub/object_validators/announce_validator.ex [new file with mode: 0644]
test/web/activity_pub/object_validator_test.exs

index 4a247ad0ca425834e032d8c01df612c6ea3f5fa4..63f89c2b4fed0baf79728b0aa03a2c79f89c5a35 100644 (file)
@@ -83,6 +83,20 @@ defmodule Pleroma.Web.ActivityPub.Builder do
     end
   end
 
+  def announce(actor, object) do
+    to = [actor.follower_address, object.data["actor"]]
+
+    {:ok,
+     %{
+       "id" => Utils.generate_activity_id(),
+       "actor" => actor.ap_id,
+       "object" => object.data["id"],
+       "to" => to,
+       "context" => object.data["context"],
+       "type" => "Announce"
+     }, []}
+  end
+
   @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
   defp object_action(actor, object) do
     object_actor = User.get_cached_by_ap_id(object.data["actor"])
index 549e5e761e7b5f83983861f3291e019b8fc9a4b9..600e58123e60c5e311969b83237346bc157807f0 100644 (file)
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
 
   alias Pleroma.Object
   alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@@ -58,6 +59,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
     end
   end
 
+  def validate(%{"type" => "Announce"} = object, meta) do
+    with {:ok, object} <-
+           object
+           |> AnnounceValidator.cast_and_validate()
+           |> Ecto.Changeset.apply_action(:insert) do
+      object = stringify_keys(object |> Map.from_struct())
+      {:ok, object, meta}
+    end
+  end
+
   def stringify_keys(%{__struct__: _} = object) do
     object
     |> Map.from_struct()
diff --git a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
new file mode 100644 (file)
index 0000000..fbefaf2
--- /dev/null
@@ -0,0 +1,53 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
+  use Ecto.Schema
+
+  alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+
+  import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+  import Ecto.Changeset
+
+  @primary_key false
+
+  embedded_schema do
+    field(:id, Types.ObjectID, primary_key: true)
+    field(:type, :string)
+    field(:object, Types.ObjectID)
+    field(:actor, Types.ObjectID)
+    field(:context, :string)
+    field(:to, Types.Recipients, default: [])
+    field(:cc, Types.Recipients, default: [])
+  end
+
+  def cast_and_validate(data) do
+    data
+    |> cast_data()
+    |> validate_data()
+  end
+
+  def cast_data(data) do
+    %__MODULE__{}
+    |> changeset(data)
+  end
+
+  def changeset(struct, data) do
+    struct
+    |> cast(data, __schema__(:fields))
+    |> fix_after_cast()
+  end
+
+  def fix_after_cast(cng) do
+    cng
+  end
+
+  def validate_data(data_cng) do
+    data_cng
+    |> validate_inclusion(:type, ["Announce"])
+    |> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
+    |> validate_actor_presence()
+    |> validate_object_presence()
+  end
+end
index 96eff1c30e57c6124fec8b0d574488dbe9d91eac..9313015f1984214109a16f5e149a02f3d0812a78 100644 (file)
@@ -280,4 +280,54 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
       assert {:object, valid_like["object"]} in validated.changes
     end
   end
+
+  describe "announces" do
+    setup do
+      user = insert(:user)
+      announcer = insert(:user)
+      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
+
+      object = Object.normalize(post_activity, false)
+      {:ok, valid_announce, []} = Builder.announce(announcer, object)
+
+      %{
+        valid_announce: valid_announce,
+        user: user,
+        post_activity: post_activity,
+        announcer: announcer
+      }
+    end
+
+    test "returns ok for a valid announce", %{valid_announce: valid_announce} do
+      assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, [])
+    end
+
+    test "returns an error if the object can't be found", %{valid_announce: valid_announce} do
+      without_object =
+        valid_announce
+        |> Map.delete("object")
+
+      {:error, cng} = ObjectValidator.validate(without_object, [])
+
+      assert {:object, {"can't be blank", [validation: :required]}} in cng.errors
+
+      nonexisting_object =
+        valid_announce
+        |> Map.put("object", "https://gensokyo.2hu/objects/99999999")
+
+      {:error, cng} = ObjectValidator.validate(nonexisting_object, [])
+
+      assert {:object, {"can't find object", []}} in cng.errors
+    end
+
+    test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do
+      nonexisting_actor =
+        valid_announce
+        |> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
+
+      {:error, cng} = ObjectValidator.validate(nonexisting_actor, [])
+
+      assert {:actor, {"can't find user", []}} in cng.errors
+    end
+  end
 end