validator renaming & add validation for target
authorAlexander Strizhakov <alex.strizhakov@gmail.com>
Tue, 2 Mar 2021 14:24:06 +0000 (17:24 +0300)
committerAlexander Strizhakov <alex.strizhakov@gmail.com>
Thu, 25 Mar 2021 10:03:40 +0000 (13:03 +0300)
lib/pleroma/web/activity_pub/object_validator.ex
lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex [moved from lib/pleroma/web/activity_pub/object_validators/pin_validator.ex with 73% similarity]
lib/pleroma/web/activity_pub/object_validators/common_validations.ex
test/pleroma/web/activity_pub/transmogrifier_test.exs
test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
test/support/http_request_mock.ex

index 11432ef3817e7ddc9c7de87b35f33503f4dcf083..14c3e853180bb910af1c16fd3a3b2885b5ff9da8 100644 (file)
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
   alias Pleroma.Object.Containment
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator
+  alias Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator
@@ -30,7 +31,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
   alias Pleroma.Web.ActivityPub.ObjectValidators.EventValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
-  alias Pleroma.Web.ActivityPub.ObjectValidators.PinValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
   alias Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator
@@ -238,7 +238,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
   def validate(%{"type" => type} = object, meta) when type in ~w(Add Remove) do
     with {:ok, object} <-
            object
-           |> PinValidator.cast_and_validate()
+           |> AddRemoveValidator.cast_and_validate()
            |> Ecto.Changeset.apply_action(:insert) do
       object = stringify_keys(object)
       {:ok, object, meta}
similarity index 73%
rename from lib/pleroma/web/activity_pub/object_validators/pin_validator.ex
rename to lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex
index dca8cba6f868438cecef012f84c3951416cc6d8f..73d1c03f0fc2c78b1599cd3baefaca95ae0f2f25 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.PinValidator do
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do
   use Ecto.Schema
 
   import Ecto.Changeset
@@ -37,6 +37,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.PinValidator do
     |> validate_required([:id, :target, :object, :actor, :type, :to, :cc])
     |> validate_inclusion(:type, ~w(Add Remove))
     |> validate_actor_presence()
+    |> validate_collection_belongs_to_actor()
     |> validate_object_presence()
   end
+
+  defp validate_collection_belongs_to_actor(changeset) do
+    validate_change(changeset, :target, fn :target, target ->
+      if String.starts_with?(target, changeset.changes[:actor]) do
+        []
+      else
+        [target: "collection doesn't belong to actor"]
+      end
+    end)
+  end
 end
index 093549a45873124904298545313f2d223812109b..94043058817ec081c6d3bc4cc5a0296f8ffb142e 100644 (file)
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
   alias Pleroma.Object
   alias Pleroma.User
 
+  @spec validate_any_presence(Ecto.Changeset.t(), [atom()]) :: Ecto.Changeset.t()
   def validate_any_presence(cng, fields) do
     non_empty =
       fields
@@ -29,6 +30,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     end
   end
 
+  @spec validate_actor_presence(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
   def validate_actor_presence(cng, options \\ []) do
     field_name = Keyword.get(options, :field_name, :actor)
 
@@ -47,6 +49,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     end)
   end
 
+  @spec validate_object_presence(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
   def validate_object_presence(cng, options \\ []) do
     field_name = Keyword.get(options, :field_name, :object)
     allowed_types = Keyword.get(options, :allowed_types, false)
@@ -68,6 +71,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     end)
   end
 
+  @spec validate_object_or_user_presence(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
   def validate_object_or_user_presence(cng, options \\ []) do
     field_name = Keyword.get(options, :field_name, :object)
     options = Keyword.put(options, :field_name, field_name)
@@ -83,6 +87,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     if actor_cng.valid?, do: actor_cng, else: object_cng
   end
 
+  @spec validate_host_match(Ecto.Changeset.t(), [atom()]) :: Ecto.Changeset.t()
   def validate_host_match(cng, fields \\ [:id, :actor]) do
     if same_domain?(cng, fields) do
       cng
@@ -95,6 +100,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     end
   end
 
+  @spec validate_fields_match(Ecto.Changeset.t(), [atom()]) :: Ecto.Changeset.t()
   def validate_fields_match(cng, fields) do
     if map_unique?(cng, fields) do
       cng
@@ -122,12 +128,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
     end)
   end
 
+  @spec same_domain?(Ecto.Changeset.t(), [atom()]) :: boolean()
   def same_domain?(cng, fields \\ [:actor, :object]) do
     map_unique?(cng, fields, fn value -> URI.parse(value).host end)
   end
 
   # This figures out if a user is able to create, delete or modify something
   # based on the domain and superuser status
+  @spec validate_modification_rights(Ecto.Changeset.t()) :: Ecto.Changeset.t()
   def validate_modification_rights(cng) do
     actor = User.get_cached_by_ap_id(get_field(cng, :actor))
 
index 28d7e1e3c0d5f69d6529b3a29613420502e7a434..9bc27f89e6a8b5b218cb652b21394e0e18a889b7 100644 (file)
@@ -168,7 +168,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
         "id" => "http://localhost:400/objects/d61d6733-e256-4fe1-ab13-1e369789423d",
         "actor" => actor,
         "object" => object_url,
-        "target" => "http://example.com/users/lain/collections/featured",
+        "target" => "https://example.com/users/lain/collections/featured",
         "type" => "Remove",
         "to" => [Pleroma.Constants.as_public()],
         "cc" => ["https://example.com/users/lain/followers"]
index e0d6429100d1b1b199f80226de37de2d6a4c2a0e..99ad87d051c44b685eb3f35044a28d07b2e57e6e 100644 (file)
@@ -1209,15 +1209,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     setup do: clear_config([:instance, :max_pinned_statuses], 1)
 
     test "pin status", %{conn: conn, user: user, activity: activity} do
-      id_str = to_string(activity.id)
+      id = activity.id
 
-      assert %{"id" => ^id_str, "pinned" => true} =
+      assert %{"id" => ^id, "pinned" => true} =
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/v1/statuses/#{activity.id}/pin")
                |> json_response_and_validate_schema(200)
 
-      assert [%{"id" => ^id_str, "pinned" => true}] =
+      assert [%{"id" => ^id, "pinned" => true}] =
                conn
                |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
                |> json_response_and_validate_schema(200)
index 9e9f1c86c8bf8ea7ba11eb4dc04f493d56fc0926..8807c2d14679551e778c3cfe2661cefb6a54aec4 100644 (file)
@@ -924,7 +924,8 @@ defmodule HttpRequestMock do
        body:
          File.read!("test/fixtures/users_mock/masto_featured.json")
          |> String.replace("{{domain}}", "mastodon.social")
-         |> String.replace("{{nickname}}", "lambadalambda")
+         |> String.replace("{{nickname}}", "lambadalambda"),
+       headers: activitypub_object_headers()
      }}
   end