forked from AkkomaGang/akkoma
Transmogrifier: Handle incoming deletes for non-user objects.
This commit is contained in:
parent
db184a8eb4
commit
4dc5302f45
5 changed files with 42 additions and 31 deletions
|
@ -11,8 +11,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
||||||
|
|
||||||
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
||||||
def validate(object, meta)
|
def validate(object, meta)
|
||||||
|
|
|
@ -28,6 +28,18 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Tasks this handles:
|
||||||
|
# - Delete create activity
|
||||||
|
# - Replace object with Tombstone
|
||||||
|
# - Set up notification
|
||||||
|
def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
|
||||||
|
with %Object{} = deleted_object <- Object.normalize(deleted_object),
|
||||||
|
{:ok, _, _} <- Object.delete(deleted_object) do
|
||||||
|
Notification.create_notifications(object)
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
def handle(object, meta) do
|
def handle(object, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
|
|
@ -729,36 +729,13 @@ def handle_incoming(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: We presently assume that any actor on the same origin domain as the object being
|
|
||||||
# deleted has the rights to delete that object. A better way to validate whether or not
|
|
||||||
# the object should be deleted is to refetch the object URI, which should return either
|
|
||||||
# an error or a tombstone. This would allow us to verify that a deletion actually took
|
|
||||||
# place.
|
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data,
|
%{"type" => "Delete"} = data,
|
||||||
_options
|
_options
|
||||||
) do
|
) do
|
||||||
object_id = Utils.get_ap_id(object_id)
|
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
||||||
|
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
|
||||||
with actor <- Containment.get_actor(data),
|
|
||||||
{:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
|
|
||||||
{:ok, object} <- get_obj_helper(object_id),
|
|
||||||
:ok <- Containment.contain_origin(actor.ap_id, object.data),
|
|
||||||
{:ok, activity} <-
|
|
||||||
ActivityPub.delete(object, local: false, activity_id: id, actor: actor.ap_id) do
|
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
|
||||||
nil ->
|
|
||||||
case User.get_cached_by_ap_id(object_id) do
|
|
||||||
%User{ap_id: ^actor} = user ->
|
|
||||||
User.delete(user)
|
|
||||||
|
|
||||||
nil ->
|
|
||||||
:error
|
|
||||||
end
|
|
||||||
|
|
||||||
_e ->
|
|
||||||
:error
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
@ -15,6 +16,28 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
describe "delete objects" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, post} = CommonAPI.post(user, %{"status" => "hey"})
|
||||||
|
object = Object.normalize(post)
|
||||||
|
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
|
||||||
|
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
|
||||||
|
%{user: user, delete: delete, post: post, object: object}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it handles object deletions", %{delete: delete, post: post, object: object} do
|
||||||
|
# In object deletions, the object is replaced by a tombstone and the
|
||||||
|
# create activity is deleted
|
||||||
|
|
||||||
|
{:ok, _delete, _} = SideEffects.handle(delete)
|
||||||
|
|
||||||
|
object = Object.get_by_id(object.id)
|
||||||
|
assert object.data["type"] == "Tombstone"
|
||||||
|
refute Activity.get_by_id(post.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "like objects" do
|
describe "like objects" do
|
||||||
setup do
|
setup do
|
||||||
poster = insert(:user)
|
poster = insert(:user)
|
||||||
|
|
|
@ -68,7 +68,7 @@ test "it fails for incoming deletes with spoofed origin" do
|
||||||
|> Map.put("object", object)
|
|> Map.put("object", object)
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert capture_log(fn ->
|
||||||
:error = Transmogrifier.handle_incoming(data)
|
{:error, _} = Transmogrifier.handle_incoming(data)
|
||||||
end) =~
|
end) =~
|
||||||
"[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, :nxdomain}"
|
"[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, :nxdomain}"
|
||||||
|
|
||||||
|
@ -97,9 +97,7 @@ test "it fails for incoming user deletes with spoofed origin" do
|
||||||
|> Poison.decode!()
|
|> Poison.decode!()
|
||||||
|> Map.put("actor", ap_id)
|
|> Map.put("actor", ap_id)
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
||||||
assert :error == Transmogrifier.handle_incoming(data)
|
|
||||||
end) =~ "Object containment failed"
|
|
||||||
|
|
||||||
assert User.get_cached_by_ap_id(ap_id)
|
assert User.get_cached_by_ap_id(ap_id)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue