Merge branch 'reject' into 'develop'

Move Accepts and Rejects to the Pipeline

See merge request pleroma/pleroma!2878
This commit is contained in:
Haelwenn 2020-08-13 16:04:43 +00:00
commit f99b8a25eb
14 changed files with 449 additions and 359 deletions

View file

@ -285,32 +285,6 @@ def listen(%{to: to, actor: actor, context: context, object: object} = params) d
end end
end end
@spec accept(map()) :: {:ok, Activity.t()} | {:error, any()}
def accept(params) do
accept_or_reject("Accept", params)
end
@spec reject(map()) :: {:ok, Activity.t()} | {:error, any()}
def reject(params) do
accept_or_reject("Reject", params)
end
@spec accept_or_reject(String.t(), map()) :: {:ok, Activity.t()} | {:error, any()}
defp accept_or_reject(type, %{to: to, actor: actor, object: object} = params) do
local = Map.get(params, :local, true)
activity_id = Map.get(params, :activity_id, nil)
data =
%{"to" => to, "type" => type, "actor" => actor.ap_id, "object" => object}
|> Maps.put_if_present("id", activity_id)
with {:ok, activity} <- insert(data, local),
_ <- notify_and_stream(activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) :: @spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | nil | {:error, any()} {:ok, Activity.t()} | nil | {:error, any()}
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do def unfollow(follower, followed, activity_id \\ nil, local \\ true) do

View file

@ -14,6 +14,28 @@ defmodule Pleroma.Web.ActivityPub.Builder do
require Pleroma.Constants require Pleroma.Constants
def accept_or_reject(actor, activity, type) do
data = %{
"id" => Utils.generate_activity_id(),
"actor" => actor.ap_id,
"type" => type,
"object" => activity.data["id"],
"to" => [activity.actor]
}
{:ok, data, []}
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 = %{

View file

@ -13,6 +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.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
@ -30,6 +31,17 @@ 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" => type} = object, meta)
when type in ~w[Accept Reject] do
with {:ok, object} <-
object
|> AcceptRejectValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
end
end
def validate(%{"type" => "Follow"} = object, meta) do def validate(%{"type" => "Follow"} = object, meta) do
with {:ok, object} <- with {:ok, object} <-
object object

View file

@ -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.AcceptRejectValidator do
use Ecto.Schema
alias Pleroma.Activity
alias Pleroma.EctoType.ActivityPub.ObjectValidators
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@primary_key false
embedded_schema do
field(:id, ObjectValidators.ObjectID, primary_key: true)
field(:type, :string)
field(:object, ObjectValidators.ObjectID)
field(:actor, ObjectValidators.ObjectID)
field(:to, ObjectValidators.Recipients, default: [])
field(:cc, ObjectValidators.Recipients, default: [])
end
def cast_data(data) do
%__MODULE__{}
|> cast(data, __schema__(:fields))
end
def validate_data(cng) do
cng
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|> validate_inclusion(:type, ["Accept", "Reject"])
|> validate_actor_presence()
|> validate_object_presence(allowed_types: ["Follow"])
|> validate_accept_reject_rights()
end
def cast_and_validate(data) do
data
|> cast_data
|> validate_data
end
def validate_accept_reject_rights(cng) do
with object_id when is_binary(object_id) <- get_field(cng, :object),
%Activity{data: %{"object" => followed_actor}} <- Activity.get_by_ap_id(object_id),
true <- followed_actor == get_field(cng, :actor) do
cng
else
_e ->
cng
|> add_error(:actor, "can't accept or reject the given activity")
end
end
end

View file

@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Push alias Pleroma.Web.Push
@ -24,6 +25,59 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
def handle(object, meta \\ []) def handle(object, meta \\ [])
# Task this handles
# - Follows
# - Sends a notification
def handle(
%{
data: %{
"actor" => actor,
"type" => "Accept",
"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, "accept"),
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
Notification.update_notification_type(followed, follow_activity)
User.update_follower_count(followed)
User.update_following_count(follower)
end
{:ok, object, meta}
end
# Task this handles
# - Rejects all existing follow activities for this person
# - Updates the follow state
# - Dismisses notificatios
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)
Notification.dismiss(follow_activity)
end
{:ok, object, meta}
end
# Tasks this handle # Tasks this handle
# - Follows if possible # - Follows if possible
# - Sends a notification # - Sends a notification
@ -44,33 +98,13 @@ def handle(
{_, {:ok, _}, _, _} <- {_, {:ok, _}, _, _} <-
{:following, User.follow(follower, followed, :follow_pending), follower, followed} do {:following, User.follow(follower, followed, :follow_pending), follower, followed} do
if followed.local && !followed.locked do if followed.local && !followed.locked do
Utils.update_follow_state_for_all(object, "accept") {:ok, accept_data, _} = Builder.accept(followed, object)
FollowingRelationship.update(follower, followed, :follow_accept) {:ok, _activity, _} = Pipeline.common_pipeline(accept_data, local: true)
User.update_follower_count(followed)
User.update_following_count(follower)
%{
to: [following_user],
actor: followed,
object: follow_id,
local: true
}
|> ActivityPub.accept()
end end
else else
{:following, {:error, _}, follower, followed} -> {:following, {:error, _}, _follower, followed} ->
Utils.update_follow_state_for_all(object, "reject") {:ok, reject_data, _} = Builder.reject(followed, object)
FollowingRelationship.update(follower, followed, :follow_reject) {:ok, _activity, _} = Pipeline.common_pipeline(reject_data, local: true)
if followed.local do
%{
to: [follower.ap_id],
actor: followed,
object: follow_id,
local: true
}
|> ActivityPub.reject()
end
_ -> _ ->
nil nil

View file

@ -9,9 +9,7 @@ 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.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
alias Pleroma.Repo alias Pleroma.Repo
@ -391,32 +389,6 @@ defp fix_content(%{"mediaType" => "text/markdown", "content" => content} = objec
defp fix_content(object), do: object defp fix_content(object), do: object
defp mastodon_follow_hack(%{"id" => id, "actor" => follower_id}, followed) do
with true <- id =~ "follows",
%User{local: true} = follower <- User.get_cached_by_ap_id(follower_id),
%Activity{} = activity <- Utils.fetch_latest_follow(follower, followed) do
{:ok, activity}
else
_ -> {:error, nil}
end
end
defp mastodon_follow_hack(_, _), do: {:error, nil}
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
# Can't find the activity. This might a Mastodon 2.3 "Accept"
{:activity, nil} ->
mastodon_follow_hack(follow_object, followed)
_ ->
{: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, _ ->
@ -551,60 +523,6 @@ def handle_incoming(
end end
end end
def handle_incoming(
%{"type" => "Accept", "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, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
User.update_follower_count(followed)
User.update_following_count(follower)
Notification.update_notification_type(followed, follow_activity)
ActivityPub.accept(%{
to: follow_activity.data["to"],
type: "Accept",
actor: followed,
object: follow_activity.data["id"],
local: false,
activity_id: id
})
else
_e ->
:error
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" => "❤️",
@ -659,9 +577,10 @@ def handle_incoming(
%{"type" => type} = data, %{"type" => type} = data,
_options _options
) )
when type in ~w{Update Block Follow} 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, _} <- Pipeline.common_pipeline(data, local: false) do {:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do
{:ok, activity} {:ok, activity}
end end
end end
@ -670,7 +589,8 @@ def handle_incoming(
%{"type" => "Delete"} = data, %{"type" => "Delete"} = data,
_options _options
) do ) do
with {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do with {:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do
{:ok, activity} {:ok, activity}
else else
{:error, {:validate_object, _}} = e -> {:error, {:validate_object, _}} = e ->

View file

@ -6,9 +6,7 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.ActivityExpiration alias Pleroma.ActivityExpiration
alias Pleroma.Conversation.Participation alias Pleroma.Conversation.Participation
alias Pleroma.FollowingRelationship
alias Pleroma.Formatter alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.ThreadMute alias Pleroma.ThreadMute
alias Pleroma.User alias Pleroma.User
@ -122,33 +120,16 @@ def unfollow(follower, unfollowed) do
def accept_follow_request(follower, followed) do def accept_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed), with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follower} <- User.follow(follower, followed), {:ok, accept_data, _} <- Builder.accept(followed, follow_activity),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"), {:ok, _activity, _} <- Pipeline.common_pipeline(accept_data, local: true) do
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Accept"
}) do
Notification.update_notification_type(followed, follow_activity)
{:ok, follower} {:ok, follower}
end end
end end
def reject_follow_request(follower, followed) do def reject_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed), with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"), {:ok, reject_data, _} <- Builder.reject(followed, follow_activity),
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject), {:ok, _activity, _} <- Pipeline.common_pipeline(reject_data, local: true) do
{:ok, _notifications} <- Notification.dismiss(follow_activity),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Reject"
}) do
{:ok, follower} {:ok, follower}
end end
end end

View file

@ -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.AcceptValidationTest 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, accept_data, _} = Builder.accept(followed, follow_activity)
%{accept_data: accept_data, followed: followed}
end
test "it validates a basic 'accept'", %{accept_data: accept_data} do
assert {:ok, _, _} = ObjectValidator.validate(accept_data, [])
end
test "it fails when the actor doesn't exist", %{accept_data: accept_data} do
accept_data =
accept_data
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
assert {:error, _} = ObjectValidator.validate(accept_data, [])
end
test "it fails when the accepted activity doesn't exist", %{accept_data: accept_data} do
accept_data =
accept_data
|> Map.put("object", "https://gensokyo.2hu/users/raymoo/follows/1")
assert {:error, _} = ObjectValidator.validate(accept_data, [])
end
test "for an accepted follow, it only validates if the actor of the accept is the followed actor",
%{accept_data: accept_data} do
stranger = insert(:user)
accept_data =
accept_data
|> Map.put("actor", stranger.ap_id)
assert {:error, _} = ObjectValidator.validate(accept_data, [])
end
end

View file

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

View file

@ -0,0 +1,91 @@
# 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.Transmogrifier.AcceptHandlingTest do
use Pleroma.DataCase
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "it works for incoming accepts which were pre-accepted" do
follower = insert(:user)
followed = insert(:user)
{:ok, follower} = User.follow(follower, followed)
assert User.following?(follower, followed) == true
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
object =
accept_data["object"]
|> Map.put("actor", follower.ap_id)
|> Map.put("id", follow_activity.data["id"])
accept_data = Map.put(accept_data, "object", object)
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
refute activity.local
assert activity.data["object"] == follow_activity.data["id"]
assert activity.data["id"] == accept_data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
end
test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
follower = User.get_by_id(follower.id)
assert follower.following_count == 1
followed = User.get_by_id(followed.id)
assert followed.follower_count == 1
end
test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user)
followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
{:error, _} = Transmogrifier.handle_incoming(accept_data)
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, followed) == true
end
end

View file

@ -185,5 +185,24 @@ test "it works for incoming follow requests from hubzilla" do
assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2" assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
assert User.following?(User.get_cached_by_ap_id(data["actor"]), user) assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
end end
test "it works for incoming follows to locked account" do
pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
user = insert(:user, locked: true)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Poison.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Follow"
assert data["object"] == user.ap_id
assert data["state"] == "pending"
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert [^pending_follower] = User.get_follow_requests(user)
end
end end
end end

View file

@ -0,0 +1,67 @@
# 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.Transmogrifier.RejectHandlingTest do
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user)
followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
{:error, _} = Transmogrifier.handle_incoming(accept_data)
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, followed) == true
end
test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, follower} = User.follow(follower, followed)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
assert User.following?(follower, followed) == true
reject_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
{:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == false
end
test "it rejects activities without a valid ID" do
user = insert(:user)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Poison.decode!()
|> Map.put("object", user.ap_id)
|> Map.put("id", "")
:error = Transmogrifier.handle_incoming(data)
end
end

View file

@ -130,7 +130,7 @@ test "it works for incoming unannounces with an existing notice" do
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
end end
test "it works for incomming unfollows with an existing follow" do test "it works for incoming unfollows with an existing follow" do
user = insert(:user) user = insert(:user)
follow_data = follow_data =

View file

@ -359,7 +359,7 @@ test "it strips internal reactions" do
refute Map.has_key?(object_data, "reaction_count") refute Map.has_key?(object_data, "reaction_count")
end end
test "it works for incomming unfollows with an existing follow" do test "it works for incoming unfollows with an existing follow" do
user = insert(:user) user = insert(:user)
follow_data = follow_data =
@ -384,204 +384,6 @@ test "it works for incomming unfollows with an existing follow" do
refute User.following?(User.get_cached_by_ap_id(data["actor"]), user) refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
end end
test "it works for incoming follows to locked account" do
pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
user = insert(:user, locked: true)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Poison.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Follow"
assert data["object"] == user.ap_id
assert data["state"] == "pending"
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert [^pending_follower] = User.get_follow_requests(user)
end
test "it works for incoming accepts which were pre-accepted" do
follower = insert(:user)
followed = insert(:user)
{:ok, follower} = User.follow(follower, followed)
assert User.following?(follower, followed) == true
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
object =
accept_data["object"]
|> Map.put("actor", follower.ap_id)
|> Map.put("id", follow_activity.data["id"])
accept_data = Map.put(accept_data, "object", object)
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
refute activity.local
assert activity.data["object"] == follow_activity.data["id"]
assert activity.data["id"] == accept_data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
end
test "it works for incoming accepts which were orphaned" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
end
test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
follower = User.get_by_id(follower.id)
assert follower.following_count == 1
followed = User.get_by_id(followed.id)
assert followed.follower_count == 1
end
test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user)
followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
:error = Transmogrifier.handle_incoming(accept_data)
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, followed) == true
end
test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user)
followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
:error = Transmogrifier.handle_incoming(accept_data)
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, followed) == true
end
test "it works for incoming rejects which are orphaned" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, follower} = User.follow(follower, followed)
{:ok, _, _, _follow_activity} = CommonAPI.follow(follower, followed)
assert User.following?(follower, followed) == true
reject_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
reject_data =
Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id))
{:ok, activity} = Transmogrifier.handle_incoming(reject_data)
refute activity.local
assert activity.data["id"] == reject_data["id"]
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == false
end
test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user)
followed = insert(:user, locked: true)
{:ok, follower} = User.follow(follower, followed)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
assert User.following?(follower, followed) == true
reject_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
|> Poison.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
{:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == false
end
test "it rejects activities without a valid ID" do
user = insert(:user)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Poison.decode!()
|> Map.put("object", user.ap_id)
|> Map.put("id", "")
:error = Transmogrifier.handle_incoming(data)
end
test "skip converting the content when it is nil" do test "skip converting the content when it is nil" do
object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe" object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe"