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
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 cng
|> validate_change(field_name, fn field_name, actor -> |> validate_change(field_name, fn field_name, actor ->
if User.get_cached_by_ap_id(actor) do if User.get_cached_by_ap_id(actor) do
@ -39,25 +41,39 @@ def validate_actor_presence(cng, field_name \\ :actor) do
end) end)
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 cng
|> validate_change(field_name, fn field_name, object -> |> validate_change(field_name, fn field_name, object_id ->
if Object.get_cached_by_ap_id(object) do object = Object.get_cached_by_ap_id(object_id)
[]
else cond do
[{field_name, "can't find object"}] !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) end)
end end
def validate_object_or_user_presence(cng, field_name \\ :object) do def validate_object_or_user_presence(cng, options \\ []) do
cng field_name = Keyword.get(options, :field_name, :object)
|> validate_change(field_name, fn field_name, object -> options = Keyword.put(options, :field_name, field_name)
if Object.get_cached_by_ap_id(object) || User.get_cached_by_ap_id(object) do
[] actor_cng =
else cng
[{field_name, "can't find object"}] |> validate_actor_presence(options)
end
end) object_cng =
cng
|> validate_object_presence(options)
if actor_cng.valid?, do: actor_cng, else: object_cng
end end
end end

View file

@ -42,13 +42,23 @@ def add_deleted_activity_id(cng) do
end end
end end
@deletable_types ~w{
Answer
Article
Audio
Event
Note
Page
Question
Video
}
def validate_data(cng) do def validate_data(cng) do
cng cng
|> validate_required([:id, :type, :actor, :to, :cc, :object]) |> validate_required([:id, :type, :actor, :to, :cc, :object])
|> validate_inclusion(:type, ["Delete"]) |> validate_inclusion(:type, ["Delete"])
|> validate_actor_presence() |> validate_actor_presence()
|> validate_deletion_rights() |> validate_deletion_rights()
|> validate_object_or_user_presence() |> validate_object_or_user_presence(allowed_types: @deletable_types)
|> add_deleted_activity_id() |> add_deleted_activity_id()
end end

View file

@ -36,6 +36,7 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
# - Set up notification # - Set up notification
# - Reduce the user note count # - Reduce the user note count
# - Reduce the reply count # - Reduce the reply count
# - Stream out the activity
def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
deleted_object = deleted_object =
Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(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 defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator 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"] assert valid_post_delete["deleted_activity_id"]
end 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 test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do
assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, [])) assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, []))
end end