DeleteValidator: Only allow deletion of certain types.

This commit is contained in:
lain 2020-05-01 13:34:47 +02:00
parent 32b8386ede
commit 5f42e6629d
4 changed files with 63 additions and 17 deletions

View file

@ -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
|> 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
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_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)
|> validate_actor_presence(options)
object_cng =
cng
|> validate_object_presence(options)
if actor_cng.valid?, do: actor_cng, else: object_cng
end
end

View file

@ -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

View file

@ -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)

View file

@ -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