Transmogrifier: Move Rejects to the Pipeline
This commit is contained in:
parent
62f7cca9a1
commit
7224bf309e
|
@ -14,19 +14,28 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
|
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
@spec accept(User.t(), Activity.t()) :: {:ok, map(), keyword()}
|
def accept_or_reject(actor, activity, type) do
|
||||||
def accept(actor, accepted_activity) do
|
|
||||||
data = %{
|
data = %{
|
||||||
"id" => Utils.generate_activity_id(),
|
"id" => Utils.generate_activity_id(),
|
||||||
"actor" => actor.ap_id,
|
"actor" => actor.ap_id,
|
||||||
"type" => "Accept",
|
"type" => type,
|
||||||
"object" => accepted_activity.data["id"],
|
"object" => activity.data["id"],
|
||||||
"to" => [accepted_activity.actor]
|
"to" => [activity.actor]
|
||||||
}
|
}
|
||||||
|
|
||||||
{:ok, data, []}
|
{:ok, data, []}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec reject(User.t(), Activity.t()) :: {:ok, map(), keyword()}
|
||||||
|
def reject(actor, rejected_activity) do
|
||||||
|
accept_or_reject(actor, rejected_activity, "Reject")
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec accept(User.t(), Activity.t()) :: {:ok, map(), keyword()}
|
||||||
|
def accept(actor, accepted_activity) do
|
||||||
|
accept_or_reject(actor, accepted_activity, "Accept")
|
||||||
|
end
|
||||||
|
|
||||||
@spec follow(User.t(), User.t()) :: {:ok, map(), keyword()}
|
@spec follow(User.t(), User.t()) :: {:ok, map(), keyword()}
|
||||||
def follow(follower, followed) do
|
def follow(follower, followed) do
|
||||||
data = %{
|
data = %{
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AcceptValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
|
||||||
|
@ -31,10 +31,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
@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)
|
||||||
|
|
||||||
def validate(%{"type" => "Accept"} = object, meta) do
|
def validate(%{"type" => type} = object, meta)
|
||||||
|
when type in ~w[Accept Reject] do
|
||||||
with {:ok, object} <-
|
with {:ok, object} <-
|
||||||
object
|
object
|
||||||
|> AcceptValidator.cast_and_validate()
|
|> AcceptRejectValidator.cast_and_validate()
|
||||||
|> Ecto.Changeset.apply_action(:insert) do
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
object = stringify_keys(object)
|
object = stringify_keys(object)
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
@ -30,10 +30,10 @@ def cast_data(data) do
|
||||||
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, ["Accept"])
|
|> validate_inclusion(:type, ["Accept", "Reject"])
|
||||||
|> validate_actor_presence()
|
|> validate_actor_presence()
|
||||||
|> validate_object_presence(allowed_types: ["Follow"])
|
|> validate_object_presence(allowed_types: ["Follow"])
|
||||||
|> validate_accept_rights()
|
|> validate_accept_reject_rights()
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
@ -42,7 +42,7 @@ def cast_and_validate(data) do
|
||||||
|> validate_data
|
|> validate_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_accept_rights(cng) do
|
def validate_accept_reject_rights(cng) do
|
||||||
with object_id when is_binary(object_id) <- get_field(cng, :object),
|
with object_id when is_binary(object_id) <- get_field(cng, :object),
|
||||||
%Activity{data: %{"object" => followed_actor}} <- Activity.get_by_ap_id(object_id),
|
%Activity{data: %{"object" => followed_actor}} <- Activity.get_by_ap_id(object_id),
|
||||||
true <- followed_actor == get_field(cng, :actor) do
|
true <- followed_actor == get_field(cng, :actor) do
|
||||||
|
@ -50,7 +50,7 @@ def validate_accept_rights(cng) do
|
||||||
else
|
else
|
||||||
_e ->
|
_e ->
|
||||||
cng
|
cng
|
||||||
|> add_error(:actor, "can't accept the given activity")
|
|> add_error(:actor, "can't accept or reject the given activity")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -52,6 +52,30 @@ def handle(
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Task this handles
|
||||||
|
# - Rejects all existing follow activities for this person
|
||||||
|
# - Updates the follow state
|
||||||
|
def handle(
|
||||||
|
%{
|
||||||
|
data: %{
|
||||||
|
"actor" => actor,
|
||||||
|
"type" => "Reject",
|
||||||
|
"object" => follow_activity_id
|
||||||
|
}
|
||||||
|
} = object,
|
||||||
|
meta
|
||||||
|
) do
|
||||||
|
with %Activity{actor: follower_id} = follow_activity <-
|
||||||
|
Activity.get_by_ap_id(follow_activity_id),
|
||||||
|
%User{} = followed <- User.get_cached_by_ap_id(actor),
|
||||||
|
%User{} = follower <- User.get_cached_by_ap_id(follower_id),
|
||||||
|
{:ok, _follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject") do
|
||||||
|
FollowingRelationship.update(follower, followed, :follow_reject)
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
|
||||||
# Tasks this handle
|
# Tasks this handle
|
||||||
# - Follows if possible
|
# - Follows if possible
|
||||||
# - Sends a notification
|
# - Sends a notification
|
||||||
|
|
|
@ -9,7 +9,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EarmarkRenderer
|
alias Pleroma.EarmarkRenderer
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.FollowingRelationship
|
|
||||||
alias Pleroma.Maps
|
alias Pleroma.Maps
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Object.Containment
|
alias Pleroma.Object.Containment
|
||||||
|
@ -390,16 +389,6 @@ defp fix_content(%{"mediaType" => "text/markdown", "content" => content} = objec
|
||||||
|
|
||||||
defp fix_content(object), do: object
|
defp fix_content(object), do: object
|
||||||
|
|
||||||
defp get_follow_activity(follow_object, _followed) do
|
|
||||||
with object_id when not is_nil(object_id) <- Utils.get_ap_id(follow_object),
|
|
||||||
{_, %Activity{} = activity} <- {:activity, Activity.get_by_ap_id(object_id)} do
|
|
||||||
{:ok, activity}
|
|
||||||
else
|
|
||||||
_ ->
|
|
||||||
{:error, nil}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reduce the object list to find the reported user.
|
# Reduce the object list to find the reported user.
|
||||||
defp get_reported(objects) do
|
defp get_reported(objects) do
|
||||||
Enum.reduce_while(objects, nil, fn ap_id, _ ->
|
Enum.reduce_while(objects, nil, fn ap_id, _ ->
|
||||||
|
@ -534,31 +523,6 @@ def handle_incoming(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_incoming(
|
|
||||||
%{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => id} = data,
|
|
||||||
_options
|
|
||||||
) do
|
|
||||||
with actor <- Containment.get_actor(data),
|
|
||||||
{:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor),
|
|
||||||
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
|
||||||
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
|
|
||||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
|
|
||||||
{:ok, activity} <-
|
|
||||||
ActivityPub.reject(%{
|
|
||||||
to: follow_activity.data["to"],
|
|
||||||
type: "Reject",
|
|
||||||
actor: followed,
|
|
||||||
object: follow_activity.data["id"],
|
|
||||||
local: false,
|
|
||||||
activity_id: id
|
|
||||||
}) do
|
|
||||||
{:ok, activity}
|
|
||||||
else
|
|
||||||
_e -> :error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@misskey_reactions %{
|
@misskey_reactions %{
|
||||||
"like" => "👍",
|
"like" => "👍",
|
||||||
"love" => "❤️",
|
"love" => "❤️",
|
||||||
|
@ -613,7 +577,7 @@ def handle_incoming(
|
||||||
%{"type" => type} = data,
|
%{"type" => type} = data,
|
||||||
_options
|
_options
|
||||||
)
|
)
|
||||||
when type in ~w{Update Block Follow Accept} do
|
when type in ~w{Update Block Follow Accept Reject} do
|
||||||
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
||||||
{:ok, activity, _} <-
|
{:ok, activity, _} <-
|
||||||
Pipeline.common_pipeline(data, local: false) do
|
Pipeline.common_pipeline(data, local: false) do
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.RejectValidationTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.Pipeline
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup do
|
||||||
|
follower = insert(:user)
|
||||||
|
followed = insert(:user, local: false)
|
||||||
|
|
||||||
|
{:ok, follow_data, _} = Builder.follow(follower, followed)
|
||||||
|
{:ok, follow_activity, _} = Pipeline.common_pipeline(follow_data, local: true)
|
||||||
|
|
||||||
|
{:ok, reject_data, _} = Builder.reject(followed, follow_activity)
|
||||||
|
|
||||||
|
%{reject_data: reject_data, followed: followed}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it validates a basic 'reject'", %{reject_data: reject_data} do
|
||||||
|
assert {:ok, _, _} = ObjectValidator.validate(reject_data, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it fails when the actor doesn't exist", %{reject_data: reject_data} do
|
||||||
|
reject_data =
|
||||||
|
reject_data
|
||||||
|
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
|
||||||
|
|
||||||
|
assert {:error, _} = ObjectValidator.validate(reject_data, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it fails when the rejected activity doesn't exist", %{reject_data: reject_data} do
|
||||||
|
reject_data =
|
||||||
|
reject_data
|
||||||
|
|> Map.put("object", "https://gensokyo.2hu/users/raymoo/follows/1")
|
||||||
|
|
||||||
|
assert {:error, _} = ObjectValidator.validate(reject_data, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
test "for an rejected follow, it only validates if the actor of the reject is the followed actor",
|
||||||
|
%{reject_data: reject_data} do
|
||||||
|
stranger = insert(:user)
|
||||||
|
|
||||||
|
reject_data =
|
||||||
|
reject_data
|
||||||
|
|> Map.put("actor", stranger.ap_id)
|
||||||
|
|
||||||
|
assert {:error, _} = ObjectValidator.validate(reject_data, [])
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,7 +24,7 @@ test "it fails for incoming rejects which cannot be correlated" do
|
||||||
accept_data =
|
accept_data =
|
||||||
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
|
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
|
||||||
|
|
||||||
:error = Transmogrifier.handle_incoming(accept_data)
|
{:error, _} = Transmogrifier.handle_incoming(accept_data)
|
||||||
|
|
||||||
follower = User.get_cached_by_id(follower.id)
|
follower = User.get_cached_by_id(follower.id)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue