DeleteValidator: Only allow deletion of certain types.
This commit is contained in:
		
							parent
							
								
									32b8386ede
								
							
						
					
					
						commit
						5f42e6629d
					
				
					 4 changed files with 63 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -28,7 +28,9 @@ def validate_recipients_presence(cng, fields \\ [:to, :cc]) do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_actor_presence(cng, field_name \\ :actor) do
 | 
			
		||||
  def validate_actor_presence(cng, options \\ []) do
 | 
			
		||||
    field_name = Keyword.get(options, :field_name, :actor)
 | 
			
		||||
 | 
			
		||||
    cng
 | 
			
		||||
    |> validate_change(field_name, fn field_name, actor ->
 | 
			
		||||
      if User.get_cached_by_ap_id(actor) do
 | 
			
		||||
| 
						 | 
				
			
			@ -39,25 +41,39 @@ def validate_actor_presence(cng, field_name \\ :actor) do
 | 
			
		|||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_object_presence(cng, field_name \\ :object) do
 | 
			
		||||
  def validate_object_presence(cng, options \\ []) do
 | 
			
		||||
    field_name = Keyword.get(options, :field_name, :object)
 | 
			
		||||
    allowed_types = Keyword.get(options, :allowed_types, false)
 | 
			
		||||
 | 
			
		||||
    cng
 | 
			
		||||
    |> validate_change(field_name, fn field_name, object ->
 | 
			
		||||
      if Object.get_cached_by_ap_id(object) do
 | 
			
		||||
        []
 | 
			
		||||
      else
 | 
			
		||||
        [{field_name, "can't find object"}]
 | 
			
		||||
    |> validate_change(field_name, fn field_name, object_id ->
 | 
			
		||||
      object = Object.get_cached_by_ap_id(object_id)
 | 
			
		||||
 | 
			
		||||
      cond do
 | 
			
		||||
        !object ->
 | 
			
		||||
          [{field_name, "can't find object"}]
 | 
			
		||||
 | 
			
		||||
        object && allowed_types && object.data["type"] not in allowed_types ->
 | 
			
		||||
          [{field_name, "object not in allowed types"}]
 | 
			
		||||
 | 
			
		||||
        true ->
 | 
			
		||||
          []
 | 
			
		||||
      end
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_object_or_user_presence(cng, field_name \\ :object) do
 | 
			
		||||
    cng
 | 
			
		||||
    |> validate_change(field_name, fn field_name, object ->
 | 
			
		||||
      if Object.get_cached_by_ap_id(object) || User.get_cached_by_ap_id(object) do
 | 
			
		||||
        []
 | 
			
		||||
      else
 | 
			
		||||
        [{field_name, "can't find object"}]
 | 
			
		||||
      end
 | 
			
		||||
    end)
 | 
			
		||||
  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)
 | 
			
		||||
 | 
			
		||||
    actor_cng =
 | 
			
		||||
      cng
 | 
			
		||||
      |> validate_actor_presence(options)
 | 
			
		||||
 | 
			
		||||
    object_cng =
 | 
			
		||||
      cng
 | 
			
		||||
      |> validate_object_presence(options)
 | 
			
		||||
 | 
			
		||||
    if actor_cng.valid?, do: actor_cng, else: object_cng
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,13 +42,23 @@ def add_deleted_activity_id(cng) do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @deletable_types ~w{
 | 
			
		||||
    Answer
 | 
			
		||||
    Article
 | 
			
		||||
    Audio
 | 
			
		||||
    Event
 | 
			
		||||
    Note
 | 
			
		||||
    Page
 | 
			
		||||
    Question
 | 
			
		||||
    Video
 | 
			
		||||
  }
 | 
			
		||||
  def validate_data(cng) do
 | 
			
		||||
    cng
 | 
			
		||||
    |> validate_required([:id, :type, :actor, :to, :cc, :object])
 | 
			
		||||
    |> validate_inclusion(:type, ["Delete"])
 | 
			
		||||
    |> validate_actor_presence()
 | 
			
		||||
    |> validate_deletion_rights()
 | 
			
		||||
    |> validate_object_or_user_presence()
 | 
			
		||||
    |> validate_object_or_user_presence(allowed_types: @deletable_types)
 | 
			
		||||
    |> add_deleted_activity_id()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
 | 
			
		|||
  # - Set up notification
 | 
			
		||||
  # - Reduce the user note count
 | 
			
		||||
  # - Reduce the reply count
 | 
			
		||||
  # - Stream out the activity
 | 
			
		||||
  def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
 | 
			
		||||
    deleted_object =
 | 
			
		||||
      Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
 | 
			
		||||
  use Pleroma.DataCase
 | 
			
		||||
 | 
			
		||||
  alias Pleroma.Object
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Builder
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.ObjectValidator
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +27,24 @@ test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete}
 | 
			
		|||
      assert valid_post_delete["deleted_activity_id"]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it is invalid if the object isn't in a list of certain types", %{
 | 
			
		||||
      valid_post_delete: valid_post_delete
 | 
			
		||||
    } do
 | 
			
		||||
      object = Object.get_by_ap_id(valid_post_delete["object"])
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        object.data
 | 
			
		||||
        |> Map.put("type", "Like")
 | 
			
		||||
 | 
			
		||||
      {:ok, _object} =
 | 
			
		||||
        object
 | 
			
		||||
        |> Ecto.Changeset.change(%{data: data})
 | 
			
		||||
        |> Object.update_and_set_cache()
 | 
			
		||||
 | 
			
		||||
      {:error, cng} = ObjectValidator.validate(valid_post_delete, [])
 | 
			
		||||
      assert {:object, {"object not in allowed types", []}} in cng.errors
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do
 | 
			
		||||
      assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, []))
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue