tests consistency
This commit is contained in:
parent
6bf85440b3
commit
7dffaef479
258 changed files with 38 additions and 37 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,84 +0,0 @@
|
|||
# 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.MRF.ActivityExpirationPolicyTest do
|
||||
use ExUnit.Case, async: true
|
||||
alias Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy
|
||||
|
||||
@id Pleroma.Web.Endpoint.url() <> "/activities/cofe"
|
||||
@local_actor Pleroma.Web.Endpoint.url() <> "/users/cofe"
|
||||
|
||||
test "adds `expires_at` property" do
|
||||
assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => @id,
|
||||
"actor" => @local_actor,
|
||||
"type" => "Create",
|
||||
"object" => %{"type" => "Note"}
|
||||
})
|
||||
|
||||
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||
end
|
||||
|
||||
test "keeps existing `expires_at` if it less than the config setting" do
|
||||
expires_at = DateTime.utc_now() |> Timex.shift(days: 1)
|
||||
|
||||
assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => @id,
|
||||
"actor" => @local_actor,
|
||||
"type" => "Create",
|
||||
"expires_at" => expires_at,
|
||||
"object" => %{"type" => "Note"}
|
||||
})
|
||||
end
|
||||
|
||||
test "overwrites existing `expires_at` if it greater than the config setting" do
|
||||
too_distant_future = DateTime.utc_now() |> Timex.shift(years: 2)
|
||||
|
||||
assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => @id,
|
||||
"actor" => @local_actor,
|
||||
"type" => "Create",
|
||||
"expires_at" => too_distant_future,
|
||||
"object" => %{"type" => "Note"}
|
||||
})
|
||||
|
||||
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||
end
|
||||
|
||||
test "ignores remote activities" do
|
||||
assert {:ok, activity} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => "https://example.com/123",
|
||||
"actor" => "https://example.com/users/cofe",
|
||||
"type" => "Create",
|
||||
"object" => %{"type" => "Note"}
|
||||
})
|
||||
|
||||
refute Map.has_key?(activity, "expires_at")
|
||||
end
|
||||
|
||||
test "ignores non-Create/Note activities" do
|
||||
assert {:ok, activity} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => "https://example.com/123",
|
||||
"actor" => "https://example.com/users/cofe",
|
||||
"type" => "Follow"
|
||||
})
|
||||
|
||||
refute Map.has_key?(activity, "expires_at")
|
||||
|
||||
assert {:ok, activity} =
|
||||
ActivityExpirationPolicy.filter(%{
|
||||
"id" => "https://example.com/123",
|
||||
"actor" => "https://example.com/users/cofe",
|
||||
"type" => "Create",
|
||||
"object" => %{"type" => "Cofe"}
|
||||
})
|
||||
|
||||
refute Map.has_key?(activity, "expires_at")
|
||||
end
|
||||
end
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
# 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.MRF.AntiFollowbotPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy
|
||||
|
||||
describe "blocking based on attributes" do
|
||||
test "matches followbots by nickname" do
|
||||
actor = insert(:user, %{nickname: "followbot@example.com"})
|
||||
target = insert(:user)
|
||||
|
||||
message = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Follow",
|
||||
"actor" => actor.ap_id,
|
||||
"object" => target.ap_id,
|
||||
"id" => "https://example.com/activities/1234"
|
||||
}
|
||||
|
||||
assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "matches followbots by display name" do
|
||||
actor = insert(:user, %{name: "Federation Bot"})
|
||||
target = insert(:user)
|
||||
|
||||
message = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Follow",
|
||||
"actor" => actor.ap_id,
|
||||
"object" => target.ap_id,
|
||||
"id" => "https://example.com/activities/1234"
|
||||
}
|
||||
|
||||
assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
test "it allows non-followbots" do
|
||||
actor = insert(:user)
|
||||
target = insert(:user)
|
||||
|
||||
message = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Follow",
|
||||
"actor" => actor.ap_id,
|
||||
"object" => target.ap_id,
|
||||
"id" => "https://example.com/activities/1234"
|
||||
}
|
||||
|
||||
{:ok, _} = AntiFollowbotPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it gracefully handles nil display names" do
|
||||
actor = insert(:user, %{name: nil})
|
||||
target = insert(:user)
|
||||
|
||||
message = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Follow",
|
||||
"actor" => actor.ap_id,
|
||||
"object" => target.ap_id,
|
||||
"id" => "https://example.com/activities/1234"
|
||||
}
|
||||
|
||||
{:ok, _} = AntiFollowbotPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
# 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.MRF.AntiLinkSpamPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
import ExUnit.CaptureLog
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy
|
||||
|
||||
@linkless_message %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"content" => "hi world!"
|
||||
}
|
||||
}
|
||||
|
||||
@linkful_message %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"content" => "<a href='https://example.com'>hi world!</a>"
|
||||
}
|
||||
}
|
||||
|
||||
@response_message %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"name" => "yes",
|
||||
"type" => "Answer"
|
||||
}
|
||||
}
|
||||
|
||||
describe "with new user" do
|
||||
test "it allows posts without links" do
|
||||
user = insert(:user, local: false)
|
||||
|
||||
assert user.note_count == 0
|
||||
|
||||
message =
|
||||
@linkless_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it disallows posts with links" do
|
||||
user = insert(:user, local: false)
|
||||
|
||||
assert user.note_count == 0
|
||||
|
||||
message =
|
||||
@linkful_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it allows posts with links for local users" do
|
||||
user = insert(:user)
|
||||
|
||||
assert user.note_count == 0
|
||||
|
||||
message =
|
||||
@linkful_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with old user" do
|
||||
test "it allows posts without links" do
|
||||
user = insert(:user, note_count: 1)
|
||||
|
||||
assert user.note_count == 1
|
||||
|
||||
message =
|
||||
@linkless_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it allows posts with links" do
|
||||
user = insert(:user, note_count: 1)
|
||||
|
||||
assert user.note_count == 1
|
||||
|
||||
message =
|
||||
@linkful_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with followed new user" do
|
||||
test "it allows posts without links" do
|
||||
user = insert(:user, follower_count: 1)
|
||||
|
||||
assert user.follower_count == 1
|
||||
|
||||
message =
|
||||
@linkless_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it allows posts with links" do
|
||||
user = insert(:user, follower_count: 1)
|
||||
|
||||
assert user.follower_count == 1
|
||||
|
||||
message =
|
||||
@linkful_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with unknown actors" do
|
||||
setup do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: :get, url: "http://invalid.actor"} ->
|
||||
%Tesla.Env{status: 500, body: ""}
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "it rejects posts without links" do
|
||||
message =
|
||||
@linkless_message
|
||||
|> Map.put("actor", "http://invalid.actor")
|
||||
|
||||
assert capture_log(fn ->
|
||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||
end
|
||||
|
||||
test "it rejects posts with links" do
|
||||
message =
|
||||
@linkful_message
|
||||
|> Map.put("actor", "http://invalid.actor")
|
||||
|
||||
assert capture_log(fn ->
|
||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with contentless-objects" do
|
||||
test "it does not reject them or error out" do
|
||||
user = insert(:user, note_count: 1)
|
||||
|
||||
message =
|
||||
@response_message
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# 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.MRF.EnsureRePrependedTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.MRF.EnsureRePrepended
|
||||
|
||||
describe "rewrites summary" do
|
||||
test "it adds `re:` to summary object when child summary and parent summary equal" do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "object-summary",
|
||||
"inReplyTo" => %Activity{object: %Object{data: %{"summary" => "object-summary"}}}
|
||||
}
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res["object"]["summary"] == "re: object-summary"
|
||||
end
|
||||
|
||||
test "it adds `re:` to summary object when child summary containts re-subject of parent summary " do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "object-summary",
|
||||
"inReplyTo" => %Activity{object: %Object{data: %{"summary" => "re: object-summary"}}}
|
||||
}
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res["object"]["summary"] == "re: object-summary"
|
||||
end
|
||||
end
|
||||
|
||||
describe "skip filter" do
|
||||
test "it skip if type isn't 'Create'" do
|
||||
message = %{
|
||||
"type" => "Annotation",
|
||||
"object" => %{"summary" => "object-summary"}
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
|
||||
test "it skip if summary is empty" do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}}
|
||||
}
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
|
||||
test "it skip if inReplyTo is empty" do
|
||||
message = %{"type" => "Create", "object" => %{"summary" => "summary"}}
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
|
||||
test "it skip if parent and child summary isn't equal" do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "object-summary",
|
||||
"inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}}
|
||||
}
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
|
||||
test "it skips if the object is only a reference" do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => "somereference"
|
||||
}
|
||||
|
||||
assert {:ok, res} = EnsureRePrepended.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
# 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.MRF.ForceBotUnlistedPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy
|
||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
defp generate_messages(actor) do
|
||||
{%{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{},
|
||||
"to" => [@public, "f"],
|
||||
"cc" => [actor.follower_address, "d"]
|
||||
},
|
||||
%{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]},
|
||||
"to" => ["f", actor.follower_address],
|
||||
"cc" => ["d", @public]
|
||||
}}
|
||||
end
|
||||
|
||||
test "removes from the federated timeline by nickname heuristics 1" do
|
||||
actor = insert(:user, %{nickname: "annoying_ebooks@example.com"})
|
||||
|
||||
{message, except_message} = generate_messages(actor)
|
||||
|
||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
|
||||
test "removes from the federated timeline by nickname heuristics 2" do
|
||||
actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"})
|
||||
|
||||
{message, except_message} = generate_messages(actor)
|
||||
|
||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
|
||||
test "removes from the federated timeline by actor type Application" do
|
||||
actor = insert(:user, %{actor_type: "Application"})
|
||||
|
||||
{message, except_message} = generate_messages(actor)
|
||||
|
||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
|
||||
test "removes from the federated timeline by actor type Service" do
|
||||
actor = insert(:user, %{actor_type: "Service"})
|
||||
|
||||
{message, except_message} = generate_messages(actor)
|
||||
|
||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
end
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# 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.MRF.HellthreadPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
import Pleroma.Web.ActivityPub.MRF.HellthreadPolicy
|
||||
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
setup do
|
||||
user = insert(:user)
|
||||
|
||||
message = %{
|
||||
"actor" => user.ap_id,
|
||||
"cc" => [user.follower_address],
|
||||
"type" => "Create",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
"https://instance.tld/users/user1",
|
||||
"https://instance.tld/users/user2",
|
||||
"https://instance.tld/users/user3"
|
||||
],
|
||||
"object" => %{
|
||||
"type" => "Note"
|
||||
}
|
||||
}
|
||||
|
||||
[user: user, message: message]
|
||||
end
|
||||
|
||||
setup do: clear_config(:mrf_hellthread)
|
||||
|
||||
test "doesn't die on chat messages" do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
|
||||
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post_chat_message(user, other_user, "moin")
|
||||
|
||||
assert {:ok, _} = filter(activity.data)
|
||||
end
|
||||
|
||||
describe "reject" do
|
||||
test "rejects the message if the recipient count is above reject_threshold", %{
|
||||
message: message
|
||||
} do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
|
||||
|
||||
assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
|
||||
filter(message)
|
||||
end
|
||||
|
||||
test "does not reject the message if the recipient count is below reject_threshold", %{
|
||||
message: message
|
||||
} do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
||||
|
||||
assert {:ok, ^message} = filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delist" do
|
||||
test "delists the message if the recipient count is above delist_threshold", %{
|
||||
user: user,
|
||||
message: message
|
||||
} do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
|
||||
|
||||
{:ok, message} = filter(message)
|
||||
assert user.follower_address in message["to"]
|
||||
assert "https://www.w3.org/ns/activitystreams#Public" in message["cc"]
|
||||
end
|
||||
|
||||
test "does not delist the message if the recipient count is below delist_threshold", %{
|
||||
message: message
|
||||
} do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0})
|
||||
|
||||
assert {:ok, ^message} = filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
test "excludes follower collection and public URI from threshold count", %{message: message} do
|
||||
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
||||
|
||||
assert {:ok, ^message} = filter(message)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
# 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.MRF.KeywordPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy
|
||||
|
||||
setup do: clear_config(:mrf_keyword)
|
||||
|
||||
setup do
|
||||
Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
|
||||
end
|
||||
|
||||
describe "rejecting based on keywords" do
|
||||
test "rejects if string matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :reject], ["pun"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"content" => "just a daily reminder that compLAINer is a good pun",
|
||||
"summary" => ""
|
||||
}
|
||||
}
|
||||
|
||||
assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
|
||||
KeywordPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "rejects if string matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :reject], ["pun"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "just a daily reminder that compLAINer is a good pun",
|
||||
"content" => ""
|
||||
}
|
||||
}
|
||||
|
||||
assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
|
||||
KeywordPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "rejects if regex matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"content" => "just a daily reminder that #{content} is a good pun",
|
||||
"summary" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
|
||||
KeywordPolicy.filter(message)
|
||||
end)
|
||||
end
|
||||
|
||||
test "rejects if regex matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "just a daily reminder that #{content} is a good pun",
|
||||
"content" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
|
||||
KeywordPolicy.filter(message)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delisting from ftl based on keywords" do
|
||||
test "delists if string matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"])
|
||||
|
||||
message = %{
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"content" => "just a daily reminder that compLAINer is a good pun",
|
||||
"summary" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, result} = KeywordPolicy.filter(message)
|
||||
assert ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"]
|
||||
refute ["https://www.w3.org/ns/activitystreams#Public"] == result["to"]
|
||||
end
|
||||
|
||||
test "delists if string matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"])
|
||||
|
||||
message = %{
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"summary" => "just a daily reminder that compLAINer is a good pun",
|
||||
"content" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, result} = KeywordPolicy.filter(message)
|
||||
assert ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"]
|
||||
refute ["https://www.w3.org/ns/activitystreams#Public"] == result["to"]
|
||||
end
|
||||
|
||||
test "delists if regex matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{
|
||||
"content" => "just a daily reminder that #{content} is a good pun",
|
||||
"summary" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, result} = KeywordPolicy.filter(message)
|
||||
|
||||
["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] and
|
||||
not (["https://www.w3.org/ns/activitystreams#Public"] == result["to"])
|
||||
end)
|
||||
end
|
||||
|
||||
test "delists if regex matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{
|
||||
"summary" => "just a daily reminder that #{content} is a good pun",
|
||||
"content" => ""
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, result} = KeywordPolicy.filter(message)
|
||||
|
||||
["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] and
|
||||
not (["https://www.w3.org/ns/activitystreams#Public"] == result["to"])
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
describe "replacing keywords" do
|
||||
test "replaces keyword if string matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{"content" => "ZFS is opensource", "summary" => ""}
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"content" => result}}} = KeywordPolicy.filter(message)
|
||||
assert result == "ZFS is free software"
|
||||
end
|
||||
|
||||
test "replaces keyword if string matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{"summary" => "ZFS is opensource", "content" => ""}
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"summary" => result}}} = KeywordPolicy.filter(message)
|
||||
assert result == "ZFS is free software"
|
||||
end
|
||||
|
||||
test "replaces keyword if regex matches in content" do
|
||||
Pleroma.Config.put([:mrf_keyword, :replace], [
|
||||
{~r/open(-|\s)?source\s?(software)?/, "free software"}
|
||||
])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["opensource", "open-source", "open source"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{"content" => "ZFS is #{content}", "summary" => ""}
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"content" => result}}} = KeywordPolicy.filter(message)
|
||||
result == "ZFS is free software"
|
||||
end)
|
||||
end
|
||||
|
||||
test "replaces keyword if regex matches in summary" do
|
||||
Pleroma.Config.put([:mrf_keyword, :replace], [
|
||||
{~r/open(-|\s)?source\s?(software)?/, "free software"}
|
||||
])
|
||||
|
||||
assert true ==
|
||||
Enum.all?(["opensource", "open-source", "open source"], fn content ->
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object" => %{"summary" => "ZFS is #{content}", "content" => ""}
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"summary" => result}}} = KeywordPolicy.filter(message)
|
||||
result == "ZFS is free software"
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# 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.MRF.MediaProxyWarmingPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.HTTP
|
||||
alias Pleroma.Tests.ObanHelpers
|
||||
alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy
|
||||
|
||||
import Mock
|
||||
|
||||
@message %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"content" => "content",
|
||||
"attachment" => [
|
||||
%{"url" => [%{"href" => "http://example.com/image.jpg"}]}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
setup do: clear_config([:media_proxy, :enabled], true)
|
||||
|
||||
test "it prefetches media proxy URIs" do
|
||||
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
|
||||
MediaProxyWarmingPolicy.filter(@message)
|
||||
|
||||
ObanHelpers.perform_all()
|
||||
# Performing jobs which has been just enqueued
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
assert called(HTTP.get(:_, :_, :_))
|
||||
end
|
||||
end
|
||||
|
||||
test "it does nothing when no attachments are present" do
|
||||
object =
|
||||
@message["object"]
|
||||
|> Map.delete("attachment")
|
||||
|
||||
message =
|
||||
@message
|
||||
|> Map.put("object", object)
|
||||
|
||||
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
|
||||
MediaProxyWarmingPolicy.filter(message)
|
||||
refute called(HTTP.get(:_, :_, :_))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
# 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.MRF.MentionPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.MentionPolicy
|
||||
|
||||
setup do: clear_config(:mrf_mention)
|
||||
|
||||
test "pass filter if allow list is empty" do
|
||||
Pleroma.Config.delete([:mrf_mention])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://example.com/ok"],
|
||||
"cc" => ["https://example.com/blocked"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
describe "allow" do
|
||||
test "empty" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
test "to" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://example.com/ok"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
test "cc" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"cc" => ["https://example.com/ok"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
test "both" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://example.com/ok"],
|
||||
"cc" => ["https://example.com/ok2"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "deny" do
|
||||
test "to" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://example.com/blocked"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) ==
|
||||
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||
end
|
||||
|
||||
test "cc" do
|
||||
Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"to" => ["https://example.com/ok"],
|
||||
"cc" => ["https://example.com/blocked"]
|
||||
}
|
||||
|
||||
assert MentionPolicy.filter(message) ==
|
||||
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
# 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.MRFTest do
|
||||
use ExUnit.Case, async: true
|
||||
use Pleroma.Tests.Helpers
|
||||
alias Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
test "subdomains_regex/1" do
|
||||
assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [
|
||||
~r/^unsafe.tld$/i,
|
||||
~r/^(.*\.)*unsafe.tld$/i
|
||||
]
|
||||
end
|
||||
|
||||
describe "subdomain_match/2" do
|
||||
test "common domains" do
|
||||
regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"])
|
||||
|
||||
assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i]
|
||||
|
||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||
assert MRF.subdomain_match?(regexes, "unsafe2.tld")
|
||||
|
||||
refute MRF.subdomain_match?(regexes, "example.com")
|
||||
end
|
||||
|
||||
test "wildcard domains with one subdomain" do
|
||||
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
||||
|
||||
assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
|
||||
|
||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||
assert MRF.subdomain_match?(regexes, "sub.unsafe.tld")
|
||||
refute MRF.subdomain_match?(regexes, "anotherunsafe.tld")
|
||||
refute MRF.subdomain_match?(regexes, "unsafe.tldanother")
|
||||
end
|
||||
|
||||
test "wildcard domains with two subdomains" do
|
||||
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
||||
|
||||
assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
|
||||
|
||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||
assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld")
|
||||
refute MRF.subdomain_match?(regexes, "sub.anotherunsafe.tld")
|
||||
refute MRF.subdomain_match?(regexes, "sub.unsafe.tldanother")
|
||||
end
|
||||
|
||||
test "matches are case-insensitive" do
|
||||
regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"])
|
||||
|
||||
assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i]
|
||||
|
||||
assert MRF.subdomain_match?(regexes, "UNSAFE.TLD")
|
||||
assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD")
|
||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||
assert MRF.subdomain_match?(regexes, "unsafe2.tld")
|
||||
|
||||
refute MRF.subdomain_match?(regexes, "EXAMPLE.COM")
|
||||
refute MRF.subdomain_match?(regexes, "example.com")
|
||||
end
|
||||
end
|
||||
|
||||
describe "describe/0" do
|
||||
test "it works as expected with noop policy" do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy])
|
||||
|
||||
expected = %{
|
||||
mrf_policies: ["NoOpPolicy"],
|
||||
exclusions: false
|
||||
}
|
||||
|
||||
{:ok, ^expected} = MRF.describe()
|
||||
end
|
||||
|
||||
test "it works as expected with mock policy" do
|
||||
clear_config([:mrf, :policies], [MRFModuleMock])
|
||||
|
||||
expected = %{
|
||||
mrf_policies: ["MRFModuleMock"],
|
||||
mrf_module_mock: "some config data",
|
||||
exclusions: false
|
||||
}
|
||||
|
||||
{:ok, ^expected} = MRF.describe()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# 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.MRF.NoPlaceholderTextPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
alias Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy
|
||||
|
||||
test "it clears content object" do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{"content" => ".", "attachment" => "image"}
|
||||
}
|
||||
|
||||
assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
|
||||
assert res["object"]["content"] == ""
|
||||
|
||||
message = put_in(message, ["object", "content"], "<p>.</p>")
|
||||
assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
|
||||
assert res["object"]["content"] == ""
|
||||
end
|
||||
|
||||
@messages [
|
||||
%{
|
||||
"type" => "Create",
|
||||
"object" => %{"content" => "test", "attachment" => "image"}
|
||||
},
|
||||
%{"type" => "Create", "object" => %{"content" => "."}},
|
||||
%{"type" => "Create", "object" => %{"content" => "<p>.</p>"}}
|
||||
]
|
||||
test "it skips filter" do
|
||||
Enum.each(@messages, fn message ->
|
||||
assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
|
||||
assert res == message
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# 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.MRF.NormalizeMarkupTest do
|
||||
use Pleroma.DataCase
|
||||
alias Pleroma.Web.ActivityPub.MRF.NormalizeMarkup
|
||||
|
||||
@html_sample """
|
||||
<b>this is in bold</b>
|
||||
<p>this is a paragraph</p>
|
||||
this is a linebreak<br />
|
||||
this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
|
||||
this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a>
|
||||
this is an image: <img src="http://example.com/image.jpg"><br />
|
||||
<script>alert('hacked')</script>
|
||||
"""
|
||||
|
||||
test "it filter html tags" do
|
||||
expected = """
|
||||
<b>this is in bold</b>
|
||||
<p>this is a paragraph</p>
|
||||
this is a linebreak<br/>
|
||||
this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
|
||||
this is a link with not allowed "rel" attribute: <a href="http://example.com/">example.com</a>
|
||||
this is an image: <img src="http://example.com/image.jpg"/><br/>
|
||||
alert('hacked')
|
||||
"""
|
||||
|
||||
message = %{"type" => "Create", "object" => %{"content" => @html_sample}}
|
||||
|
||||
assert {:ok, res} = NormalizeMarkup.filter(message)
|
||||
assert res["object"]["content"] == expected
|
||||
end
|
||||
|
||||
test "it skips filter if type isn't `Create`" do
|
||||
message = %{"type" => "Note", "object" => %{}}
|
||||
|
||||
assert {:ok, res} = NormalizeMarkup.filter(message)
|
||||
assert res == message
|
||||
end
|
||||
end
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
# 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.MRF.ObjectAgePolicyTest do
|
||||
use Pleroma.DataCase
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
setup do:
|
||||
clear_config(:mrf_object_age,
|
||||
threshold: 172_800,
|
||||
actions: [:delist, :strip_followers]
|
||||
)
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp get_old_message do
|
||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||
|> Poison.decode!()
|
||||
end
|
||||
|
||||
defp get_new_message do
|
||||
old_message = get_old_message()
|
||||
|
||||
new_object =
|
||||
old_message
|
||||
|> Map.get("object")
|
||||
|> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601())
|
||||
|
||||
old_message
|
||||
|> Map.put("object", new_object)
|
||||
end
|
||||
|
||||
describe "with reject action" do
|
||||
test "works with objects with empty to or cc fields" do
|
||||
Config.put([:mrf_object_age, :actions], [:reject])
|
||||
|
||||
data =
|
||||
get_old_message()
|
||||
|> Map.put("cc", nil)
|
||||
|> Map.put("to", nil)
|
||||
|
||||
assert match?({:reject, _}, ObjectAgePolicy.filter(data))
|
||||
end
|
||||
|
||||
test "it rejects an old post" do
|
||||
Config.put([:mrf_object_age, :actions], [:reject])
|
||||
|
||||
data = get_old_message()
|
||||
|
||||
assert match?({:reject, _}, ObjectAgePolicy.filter(data))
|
||||
end
|
||||
|
||||
test "it allows a new post" do
|
||||
Config.put([:mrf_object_age, :actions], [:reject])
|
||||
|
||||
data = get_new_message()
|
||||
|
||||
assert match?({:ok, _}, ObjectAgePolicy.filter(data))
|
||||
end
|
||||
end
|
||||
|
||||
describe "with delist action" do
|
||||
test "works with objects with empty to or cc fields" do
|
||||
Config.put([:mrf_object_age, :actions], [:delist])
|
||||
|
||||
data =
|
||||
get_old_message()
|
||||
|> Map.put("cc", nil)
|
||||
|> Map.put("to", nil)
|
||||
|
||||
{:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
{:ok, data} = ObjectAgePolicy.filter(data)
|
||||
|
||||
assert Visibility.get_visibility(%{data: data}) == "unlisted"
|
||||
end
|
||||
|
||||
test "it delists an old post" do
|
||||
Config.put([:mrf_object_age, :actions], [:delist])
|
||||
|
||||
data = get_old_message()
|
||||
|
||||
{:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
{:ok, data} = ObjectAgePolicy.filter(data)
|
||||
|
||||
assert Visibility.get_visibility(%{data: data}) == "unlisted"
|
||||
end
|
||||
|
||||
test "it allows a new post" do
|
||||
Config.put([:mrf_object_age, :actions], [:delist])
|
||||
|
||||
data = get_new_message()
|
||||
|
||||
{:ok, _user} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
assert match?({:ok, ^data}, ObjectAgePolicy.filter(data))
|
||||
end
|
||||
end
|
||||
|
||||
describe "with strip_followers action" do
|
||||
test "works with objects with empty to or cc fields" do
|
||||
Config.put([:mrf_object_age, :actions], [:strip_followers])
|
||||
|
||||
data =
|
||||
get_old_message()
|
||||
|> Map.put("cc", nil)
|
||||
|> Map.put("to", nil)
|
||||
|
||||
{:ok, user} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
{:ok, data} = ObjectAgePolicy.filter(data)
|
||||
|
||||
refute user.follower_address in data["to"]
|
||||
refute user.follower_address in data["cc"]
|
||||
end
|
||||
|
||||
test "it strips followers collections from an old post" do
|
||||
Config.put([:mrf_object_age, :actions], [:strip_followers])
|
||||
|
||||
data = get_old_message()
|
||||
|
||||
{:ok, user} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
{:ok, data} = ObjectAgePolicy.filter(data)
|
||||
|
||||
refute user.follower_address in data["to"]
|
||||
refute user.follower_address in data["cc"]
|
||||
end
|
||||
|
||||
test "it allows a new post" do
|
||||
Config.put([:mrf_object_age, :actions], [:strip_followers])
|
||||
|
||||
data = get_new_message()
|
||||
|
||||
{:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
assert match?({:ok, ^data}, ObjectAgePolicy.filter(data))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
# 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.MRF.RejectNonPublicTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.RejectNonPublic
|
||||
|
||||
setup do: clear_config([:mrf_rejectnonpublic])
|
||||
|
||||
describe "public message" do
|
||||
test "it's allowed when address is public" do
|
||||
actor = insert(:user, follower_address: "test-address")
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
assert {:ok, message} = RejectNonPublic.filter(message)
|
||||
end
|
||||
|
||||
test "it's allowed when cc address contain public address" do
|
||||
actor = insert(:user, follower_address: "test-address")
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
assert {:ok, message} = RejectNonPublic.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "followers message" do
|
||||
test "it's allowed when addrer of message in the follower addresses of user and it enabled in config" do
|
||||
actor = insert(:user, follower_address: "test-address")
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["test-address"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true)
|
||||
assert {:ok, message} = RejectNonPublic.filter(message)
|
||||
end
|
||||
|
||||
test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do
|
||||
actor = insert(:user, follower_address: "test-address")
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["test-address"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false)
|
||||
assert {:reject, _} = RejectNonPublic.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "direct message" do
|
||||
test "it's allows when direct messages are allow" do
|
||||
actor = insert(:user)
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true)
|
||||
assert {:ok, message} = RejectNonPublic.filter(message)
|
||||
end
|
||||
|
||||
test "it's reject when direct messages aren't allow" do
|
||||
actor = insert(:user)
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Publid~~~"],
|
||||
"cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false)
|
||||
assert {:reject, _} = RejectNonPublic.filter(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,539 +0,0 @@
|
|||
# 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.MRF.SimplePolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Web.ActivityPub.MRF.SimplePolicy
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
setup do:
|
||||
clear_config(:mrf_simple,
|
||||
media_removal: [],
|
||||
media_nsfw: [],
|
||||
federated_timeline_removal: [],
|
||||
report_removal: [],
|
||||
reject: [],
|
||||
followers_only: [],
|
||||
accept: [],
|
||||
avatar_removal: [],
|
||||
banner_removal: [],
|
||||
reject_deletes: []
|
||||
)
|
||||
|
||||
describe "when :media_removal" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :media_removal], [])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
Config.put([:mrf_simple, :media_removal], ["remote.instance"])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) ==
|
||||
{:ok,
|
||||
media_message
|
||||
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
Config.put([:mrf_simple, :media_removal], ["*.remote.instance"])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) ==
|
||||
{:ok,
|
||||
media_message
|
||||
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :media_nsfw" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :media_nsfw], [])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
Config.put([:mrf_simple, :media_nsfw], ["remote.instance"])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) ==
|
||||
{:ok,
|
||||
media_message
|
||||
|> put_in(["object", "tag"], ["foo", "nsfw"])
|
||||
|> put_in(["object", "sensitive"], true)}
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
Config.put([:mrf_simple, :media_nsfw], ["*.remote.instance"])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(media_message) ==
|
||||
{:ok,
|
||||
media_message
|
||||
|> put_in(["object", "tag"], ["foo", "nsfw"])
|
||||
|> put_in(["object", "sensitive"], true)}
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
end
|
||||
|
||||
defp build_media_message do
|
||||
%{
|
||||
"actor" => "https://remote.instance/users/bob",
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"attachment" => [%{}],
|
||||
"tag" => ["foo"],
|
||||
"sensitive" => false
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
describe "when :report_removal" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :report_removal], [])
|
||||
report_message = build_report_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(report_message) == {:ok, report_message}
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
Config.put([:mrf_simple, :report_removal], ["remote.instance"])
|
||||
report_message = build_report_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(report_message)
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
Config.put([:mrf_simple, :report_removal], ["*.remote.instance"])
|
||||
report_message = build_report_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(report_message)
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
end
|
||||
|
||||
defp build_report_message do
|
||||
%{
|
||||
"actor" => "https://remote.instance/users/bob",
|
||||
"type" => "Flag"
|
||||
}
|
||||
end
|
||||
|
||||
describe "when :federated_timeline_removal" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :federated_timeline_removal], [])
|
||||
{_, ftl_message} = build_ftl_actor_and_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
{actor, ftl_message} = build_ftl_actor_and_message()
|
||||
|
||||
ftl_message_actor_host =
|
||||
ftl_message
|
||||
|> Map.fetch!("actor")
|
||||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
assert actor.follower_address in ftl_message["to"]
|
||||
refute actor.follower_address in ftl_message["cc"]
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
||||
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
{actor, ftl_message} = build_ftl_actor_and_message()
|
||||
|
||||
ftl_message_actor_host =
|
||||
ftl_message
|
||||
|> Map.fetch!("actor")
|
||||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
Config.put([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host])
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
assert actor.follower_address in ftl_message["to"]
|
||||
refute actor.follower_address in ftl_message["cc"]
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
||||
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host but only as:Public in to" do
|
||||
{_actor, ftl_message} = build_ftl_actor_and_message()
|
||||
|
||||
ftl_message_actor_host =
|
||||
ftl_message
|
||||
|> Map.fetch!("actor")
|
||||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
ftl_message = Map.put(ftl_message, "cc", [])
|
||||
|
||||
Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
||||
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
||||
end
|
||||
end
|
||||
|
||||
defp build_ftl_actor_and_message do
|
||||
actor = insert(:user)
|
||||
|
||||
{actor,
|
||||
%{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
|
||||
"cc" => [actor.follower_address, "http://foo.bar/qux"]
|
||||
}}
|
||||
end
|
||||
|
||||
describe "when :reject" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :reject], [])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "activity has a matching host" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
||||
end
|
||||
|
||||
test "activity matches with wildcard domain" do
|
||||
Config.put([:mrf_simple, :reject], ["*.remote.instance"])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
||||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(remote_user)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :followers_only" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :followers_only], [])
|
||||
{_, ftl_message} = build_ftl_actor_and_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
actor = insert(:user)
|
||||
following_user = insert(:user)
|
||||
non_following_user = insert(:user)
|
||||
|
||||
{:ok, _, _, _} = CommonAPI.follow(following_user, actor)
|
||||
|
||||
activity = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
following_user.ap_id,
|
||||
non_following_user.ap_id
|
||||
],
|
||||
"cc" => [actor.follower_address, "http://foo.bar/qux"]
|
||||
}
|
||||
|
||||
dm_activity = %{
|
||||
"actor" => actor.ap_id,
|
||||
"to" => [
|
||||
following_user.ap_id,
|
||||
non_following_user.ap_id
|
||||
],
|
||||
"cc" => []
|
||||
}
|
||||
|
||||
actor_domain =
|
||||
activity
|
||||
|> Map.fetch!("actor")
|
||||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
Config.put([:mrf_simple, :followers_only], [actor_domain])
|
||||
|
||||
assert {:ok, new_activity} = SimplePolicy.filter(activity)
|
||||
assert actor.follower_address in new_activity["cc"]
|
||||
assert following_user.ap_id in new_activity["to"]
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
|
||||
refute non_following_user.ap_id in new_activity["to"]
|
||||
refute non_following_user.ap_id in new_activity["cc"]
|
||||
|
||||
assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
|
||||
assert new_dm_activity["to"] == [following_user.ap_id]
|
||||
assert new_dm_activity["cc"] == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :accept" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :accept], [])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "is not empty but activity doesn't have a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
||||
end
|
||||
|
||||
test "activity has a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["remote.instance"])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "activity matches with wildcard domain" do
|
||||
Config.put([:mrf_simple, :accept], ["*.remote.instance"])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :avatar_removal" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :avatar_removal], [])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
|
||||
test "is not empty but it doesn't have a matching host" do
|
||||
Config.put([:mrf_simple, :avatar_removal], ["non.matching.remote"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
Config.put([:mrf_simple, :avatar_removal], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
||||
refute filtered["icon"]
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
Config.put([:mrf_simple, :avatar_removal], ["*.remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
||||
refute filtered["icon"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :banner_removal" do
|
||||
test "is empty" do
|
||||
Config.put([:mrf_simple, :banner_removal], [])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
|
||||
test "is not empty but it doesn't have a matching host" do
|
||||
Config.put([:mrf_simple, :banner_removal], ["non.matching.remote"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
Config.put([:mrf_simple, :banner_removal], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
||||
refute filtered["image"]
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
Config.put([:mrf_simple, :banner_removal], ["*.remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
||||
refute filtered["image"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :reject_deletes is empty" do
|
||||
setup do: Config.put([:mrf_simple, :reject_deletes], [])
|
||||
|
||||
test "it accepts deletions even from rejected servers" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||
end
|
||||
|
||||
test "it accepts deletions even from non-whitelisted servers" do
|
||||
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
|
||||
setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"])
|
||||
|
||||
test "it accepts deletions even from rejected servers" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||
end
|
||||
|
||||
test "it accepts deletions even from non-whitelisted servers" do
|
||||
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :reject_deletes has a matching host" do
|
||||
setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"])
|
||||
|
||||
test "it rejects the deletion" do
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(deletion_message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :reject_deletes match with wildcard domain" do
|
||||
setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"])
|
||||
|
||||
test "it rejects the deletion" do
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
assert {:reject, _} = SimplePolicy.filter(deletion_message)
|
||||
end
|
||||
end
|
||||
|
||||
defp build_local_message do
|
||||
%{
|
||||
"actor" => "#{Pleroma.Web.base_url()}/users/alice",
|
||||
"to" => [],
|
||||
"cc" => []
|
||||
}
|
||||
end
|
||||
|
||||
defp build_remote_message do
|
||||
%{"actor" => "https://remote.instance/users/bob"}
|
||||
end
|
||||
|
||||
defp build_remote_user do
|
||||
%{
|
||||
"id" => "https://remote.instance/users/bob",
|
||||
"icon" => %{
|
||||
"url" => "http://example.com/image.jpg",
|
||||
"type" => "Image"
|
||||
},
|
||||
"image" => %{
|
||||
"url" => "http://example.com/image.jpg",
|
||||
"type" => "Image"
|
||||
},
|
||||
"type" => "Person"
|
||||
}
|
||||
end
|
||||
|
||||
defp build_remote_deletion_message do
|
||||
%{
|
||||
"type" => "Delete",
|
||||
"actor" => "https://remote.instance/users/bob"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
# 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.MRF.StealEmojiPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
setup do
|
||||
emoji_path = Path.join(Config.get([:instance, :static_dir]), "emoji/stolen")
|
||||
File.rm_rf!(emoji_path)
|
||||
File.mkdir!(emoji_path)
|
||||
|
||||
Pleroma.Emoji.reload()
|
||||
|
||||
on_exit(fn ->
|
||||
File.rm_rf!(emoji_path)
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "does nothing by default" do
|
||||
installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
|
||||
refute "firedfox" in installed_emoji
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}],
|
||||
"actor" => "https://example.org/users/admin"
|
||||
}
|
||||
}
|
||||
|
||||
assert {:ok, message} == StealEmojiPolicy.filter(message)
|
||||
|
||||
installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
|
||||
refute "firedfox" in installed_emoji
|
||||
end
|
||||
|
||||
test "Steals emoji on unknown shortcode from allowed remote host" do
|
||||
installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
|
||||
refute "firedfox" in installed_emoji
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}],
|
||||
"actor" => "https://example.org/users/admin"
|
||||
}
|
||||
}
|
||||
|
||||
clear_config([:mrf_steal_emoji, :hosts], ["example.org"])
|
||||
clear_config([:mrf_steal_emoji, :size_limit], 284_468)
|
||||
|
||||
assert {:ok, message} == StealEmojiPolicy.filter(message)
|
||||
|
||||
installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
|
||||
assert "firedfox" in installed_emoji
|
||||
end
|
||||
end
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
# 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.MRF.SubchainPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.DropPolicy
|
||||
alias Pleroma.Web.ActivityPub.MRF.SubchainPolicy
|
||||
|
||||
@message %{
|
||||
"actor" => "https://banned.com",
|
||||
"type" => "Create",
|
||||
"object" => %{"content" => "hi"}
|
||||
}
|
||||
setup do: clear_config([:mrf_subchain, :match_actor])
|
||||
|
||||
test "it matches and processes subchains when the actor matches a configured target" do
|
||||
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
|
||||
~r/^https:\/\/banned.com/s => [DropPolicy]
|
||||
})
|
||||
|
||||
{:reject, _} = SubchainPolicy.filter(@message)
|
||||
end
|
||||
|
||||
test "it doesn't match and process subchains when the actor doesn't match a configured target" do
|
||||
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
|
||||
~r/^https:\/\/borked.com/s => [DropPolicy]
|
||||
})
|
||||
|
||||
{:ok, _message} = SubchainPolicy.filter(@message)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
# 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.MRF.TagPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.TagPolicy
|
||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
describe "mrf_tag:disable-any-subscription" do
|
||||
test "rejects message" do
|
||||
actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"])
|
||||
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => actor.ap_id}
|
||||
assert {:reject, _} = TagPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "mrf_tag:disable-remote-subscription" do
|
||||
test "rejects non-local follow requests" do
|
||||
actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
|
||||
follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false)
|
||||
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
|
||||
assert {:reject, _} = TagPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "allows non-local follow requests" do
|
||||
actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
|
||||
follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true)
|
||||
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
|
||||
assert {:ok, message} = TagPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "mrf_tag:sandbox" do
|
||||
test "removes from public timelines" do
|
||||
actor = insert(:user, tags: ["mrf_tag:sandbox"])
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{},
|
||||
"to" => [@public, "f"],
|
||||
"cc" => [@public, "d"]
|
||||
}
|
||||
|
||||
except_message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"to" => ["f", actor.follower_address], "cc" => ["d"]},
|
||||
"to" => ["f", actor.follower_address],
|
||||
"cc" => ["d"]
|
||||
}
|
||||
|
||||
assert TagPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "mrf_tag:force-unlisted" do
|
||||
test "removes from the federated timeline" do
|
||||
actor = insert(:user, tags: ["mrf_tag:force-unlisted"])
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{},
|
||||
"to" => [@public, "f"],
|
||||
"cc" => [actor.follower_address, "d"]
|
||||
}
|
||||
|
||||
except_message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]},
|
||||
"to" => ["f", actor.follower_address],
|
||||
"cc" => ["d", @public]
|
||||
}
|
||||
|
||||
assert TagPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "mrf_tag:media-strip" do
|
||||
test "removes attachments" do
|
||||
actor = insert(:user, tags: ["mrf_tag:media-strip"])
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"attachment" => ["file1"]}
|
||||
}
|
||||
|
||||
except_message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{}
|
||||
}
|
||||
|
||||
assert TagPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
end
|
||||
|
||||
describe "mrf_tag:media-force-nsfw" do
|
||||
test "Mark as sensitive on presence of attachments" do
|
||||
actor = insert(:user, tags: ["mrf_tag:media-force-nsfw"])
|
||||
|
||||
message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"tag" => ["test"], "attachment" => ["file1"]}
|
||||
}
|
||||
|
||||
except_message = %{
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Create",
|
||||
"object" => %{"tag" => ["test", "nsfw"], "attachment" => ["file1"], "sensitive" => true}
|
||||
}
|
||||
|
||||
assert TagPolicy.filter(message) == {:ok, except_message}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# 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.MRF.UserAllowListPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy
|
||||
|
||||
setup do: clear_config(:mrf_user_allowlist)
|
||||
|
||||
test "pass filter if allow list is empty" do
|
||||
actor = insert(:user)
|
||||
message = %{"actor" => actor.ap_id}
|
||||
assert UserAllowListPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
test "pass filter if allow list isn't empty and user in allow list" do
|
||||
actor = insert(:user)
|
||||
Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]})
|
||||
message = %{"actor" => actor.ap_id}
|
||||
assert UserAllowListPolicy.filter(message) == {:ok, message}
|
||||
end
|
||||
|
||||
test "rejected if allow list isn't empty and user not in allow list" do
|
||||
actor = insert(:user)
|
||||
Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})
|
||||
message = %{"actor" => actor.ap_id}
|
||||
assert {:reject, _} = UserAllowListPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
# 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.MRF.VocabularyPolicyTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.VocabularyPolicy
|
||||
|
||||
describe "accept" do
|
||||
setup do: clear_config([:mrf_vocabulary, :accept])
|
||||
|
||||
test "it accepts based on parent activity type" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"])
|
||||
|
||||
message = %{
|
||||
"type" => "Like",
|
||||
"object" => "whatever"
|
||||
}
|
||||
|
||||
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it accepts based on child object type" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"content" => "whatever"
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it does not accept disallowed child objects" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"type" => "Article",
|
||||
"content" => "whatever"
|
||||
}
|
||||
}
|
||||
|
||||
{:reject, _} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it does not accept disallowed parent types" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"content" => "whatever"
|
||||
}
|
||||
}
|
||||
|
||||
{:reject, _} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "reject" do
|
||||
setup do: clear_config([:mrf_vocabulary, :reject])
|
||||
|
||||
test "it rejects based on parent activity type" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
|
||||
|
||||
message = %{
|
||||
"type" => "Like",
|
||||
"object" => "whatever"
|
||||
}
|
||||
|
||||
{:reject, _} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it rejects based on child object type" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"])
|
||||
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"content" => "whatever"
|
||||
}
|
||||
}
|
||||
|
||||
{:reject, _} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
|
||||
test "it passes through objects that aren't disallowed" do
|
||||
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
|
||||
|
||||
message = %{
|
||||
"type" => "Announce",
|
||||
"object" => "whatever"
|
||||
}
|
||||
|
||||
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
# 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.Types.DateTimeTest do
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime
|
||||
use Pleroma.DataCase
|
||||
|
||||
test "it validates an xsd:Datetime" do
|
||||
valid_strings = [
|
||||
"2004-04-12T13:20:00",
|
||||
"2004-04-12T13:20:15.5",
|
||||
"2004-04-12T13:20:00-05:00",
|
||||
"2004-04-12T13:20:00Z"
|
||||
]
|
||||
|
||||
invalid_strings = [
|
||||
"2004-04-12T13:00",
|
||||
"2004-04-1213:20:00",
|
||||
"99-04-12T13:00",
|
||||
"2004-04-12"
|
||||
]
|
||||
|
||||
assert {:ok, "2004-04-01T12:00:00Z"} == DateTime.cast("2004-04-01T12:00:00Z")
|
||||
|
||||
Enum.each(valid_strings, fn date_time ->
|
||||
result = DateTime.cast(date_time)
|
||||
assert {:ok, _} = result
|
||||
end)
|
||||
|
||||
Enum.each(invalid_strings, fn date_time ->
|
||||
result = DateTime.cast(date_time)
|
||||
assert :error == result
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID
|
||||
use Pleroma.DataCase
|
||||
|
||||
@uris [
|
||||
"http://lain.com/users/lain",
|
||||
"http://lain.com",
|
||||
"https://lain.com/object/1"
|
||||
]
|
||||
|
||||
@non_uris [
|
||||
"https://",
|
||||
"rin",
|
||||
1,
|
||||
:x,
|
||||
%{"1" => 2}
|
||||
]
|
||||
|
||||
test "it accepts http uris" do
|
||||
Enum.each(@uris, fn uri ->
|
||||
assert {:ok, uri} == ObjectID.cast(uri)
|
||||
end)
|
||||
end
|
||||
|
||||
test "it accepts an object with a nested uri id" do
|
||||
Enum.each(@uris, fn uri ->
|
||||
assert {:ok, uri} == ObjectID.cast(%{"id" => uri})
|
||||
end)
|
||||
end
|
||||
|
||||
test "it rejects non-uri strings" do
|
||||
Enum.each(@non_uris, fn non_uri ->
|
||||
assert :error == ObjectID.cast(non_uri)
|
||||
assert :error == ObjectID.cast(%{"id" => non_uri})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients
|
||||
use Pleroma.DataCase
|
||||
|
||||
test "it asserts that all elements of the list are object ids" do
|
||||
list = ["https://lain.com/users/lain", "invalid"]
|
||||
|
||||
assert :error == Recipients.cast(list)
|
||||
end
|
||||
|
||||
test "it works with a list" do
|
||||
list = ["https://lain.com/users/lain"]
|
||||
assert {:ok, list} == Recipients.cast(list)
|
||||
end
|
||||
|
||||
test "it works with a list with whole objects" do
|
||||
list = ["https://lain.com/users/lain", %{"id" => "https://gensokyo.2hu/users/raymoo"}]
|
||||
resulting_list = ["https://gensokyo.2hu/users/raymoo", "https://lain.com/users/lain"]
|
||||
assert {:ok, resulting_list} == Recipients.cast(list)
|
||||
end
|
||||
|
||||
test "it turns a single string into a list" do
|
||||
recipient = "https://lain.com/users/lain"
|
||||
|
||||
assert {:ok, [recipient]} == Recipients.cast(recipient)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
# 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.Types.SafeTextTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText
|
||||
|
||||
test "it lets normal text go through" do
|
||||
text = "hey how are you"
|
||||
assert {:ok, text} == SafeText.cast(text)
|
||||
end
|
||||
|
||||
test "it removes html tags from text" do
|
||||
text = "hey look xss <script>alert('foo')</script>"
|
||||
assert {:ok, "hey look xss alert('foo')"} == SafeText.cast(text)
|
||||
end
|
||||
|
||||
test "it keeps basic html tags" do
|
||||
text = "hey <a href='http://gensokyo.2hu'>look</a> xss <script>alert('foo')</script>"
|
||||
|
||||
assert {:ok, "hey <a href=\"http://gensokyo.2hu\">look</a> xss alert('foo')"} ==
|
||||
SafeText.cast(text)
|
||||
end
|
||||
|
||||
test "errors for non-text" do
|
||||
assert :error == SafeText.cast(1)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
# 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.PipelineTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Mock
|
||||
import Pleroma.Factory
|
||||
|
||||
describe "common_pipeline/2" do
|
||||
setup do
|
||||
clear_config([:instance, :federating], true)
|
||||
:ok
|
||||
end
|
||||
|
||||
test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do
|
||||
activity = insert(:note_activity)
|
||||
object = %{"id" => "1", "type" => "Love"}
|
||||
meta = [local: true, object_data: object]
|
||||
|
||||
activity_with_object = %{activity | data: Map.put(activity.data, "object", object)}
|
||||
|
||||
with_mocks([
|
||||
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.MRF,
|
||||
[],
|
||||
[pipeline_filter: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.ActivityPub,
|
||||
[],
|
||||
[persist: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.SideEffects,
|
||||
[],
|
||||
[
|
||||
handle: fn o, m -> {:ok, o, m} end,
|
||||
handle_after_transaction: fn m -> m end
|
||||
]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Federator,
|
||||
[],
|
||||
[publish: fn _o -> :ok end]
|
||||
}
|
||||
]) do
|
||||
assert {:ok, ^activity, ^meta} =
|
||||
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
|
||||
|
||||
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
assert_called(Pleroma.Web.Federator.publish(activity_with_object))
|
||||
end
|
||||
end
|
||||
|
||||
test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
|
||||
activity = insert(:note_activity)
|
||||
meta = [local: true]
|
||||
|
||||
with_mocks([
|
||||
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.MRF,
|
||||
[],
|
||||
[pipeline_filter: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.ActivityPub,
|
||||
[],
|
||||
[persist: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.SideEffects,
|
||||
[],
|
||||
[
|
||||
handle: fn o, m -> {:ok, o, m} end,
|
||||
handle_after_transaction: fn m -> m end
|
||||
]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Federator,
|
||||
[],
|
||||
[publish: fn _o -> :ok end]
|
||||
}
|
||||
]) do
|
||||
assert {:ok, ^activity, ^meta} =
|
||||
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
|
||||
|
||||
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
|
||||
assert_called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
||||
test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do
|
||||
activity = insert(:note_activity)
|
||||
meta = [local: false]
|
||||
|
||||
with_mocks([
|
||||
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.MRF,
|
||||
[],
|
||||
[pipeline_filter: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.ActivityPub,
|
||||
[],
|
||||
[persist: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.SideEffects,
|
||||
[],
|
||||
[handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Federator,
|
||||
[],
|
||||
[]
|
||||
}
|
||||
]) do
|
||||
assert {:ok, ^activity, ^meta} =
|
||||
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
|
||||
|
||||
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
|
||||
end
|
||||
end
|
||||
|
||||
test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do
|
||||
clear_config([:instance, :federating], false)
|
||||
|
||||
activity = insert(:note_activity)
|
||||
meta = [local: true]
|
||||
|
||||
with_mocks([
|
||||
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.MRF,
|
||||
[],
|
||||
[pipeline_filter: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.ActivityPub,
|
||||
[],
|
||||
[persist: fn o, m -> {:ok, o, m} end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.ActivityPub.SideEffects,
|
||||
[],
|
||||
[handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Federator,
|
||||
[],
|
||||
[]
|
||||
}
|
||||
]) do
|
||||
assert {:ok, ^activity, ^meta} =
|
||||
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
|
||||
|
||||
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
|
||||
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,365 +0,0 @@
|
|||
# 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.PublisherTest do
|
||||
use Pleroma.Web.ConnCase
|
||||
|
||||
import ExUnit.CaptureLog
|
||||
import Pleroma.Factory
|
||||
import Tesla.Mock
|
||||
import Mock
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Instances
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Publisher
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
@as_public "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
setup do
|
||||
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
setup_all do: clear_config([:instance, :federating], true)
|
||||
|
||||
describe "gather_webfinger_links/1" do
|
||||
test "it returns links" do
|
||||
user = insert(:user)
|
||||
|
||||
expected_links = [
|
||||
%{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
|
||||
%{
|
||||
"href" => user.ap_id,
|
||||
"rel" => "self",
|
||||
"type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||
},
|
||||
%{
|
||||
"rel" => "http://ostatus.org/schema/1.0/subscribe",
|
||||
"template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
|
||||
}
|
||||
]
|
||||
|
||||
assert expected_links == Publisher.gather_webfinger_links(user)
|
||||
end
|
||||
end
|
||||
|
||||
describe "determine_inbox/2" do
|
||||
test "it returns sharedInbox for messages involving as:Public in to" do
|
||||
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"to" => [@as_public], "cc" => [user.follower_address]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns sharedInbox for messages involving as:Public in cc" do
|
||||
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"cc" => [@as_public], "to" => [user.follower_address]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns sharedInbox for messages involving multiple recipients in to" do
|
||||
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
|
||||
user_two = insert(:user)
|
||||
user_three = insert(:user)
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns sharedInbox for messages involving multiple recipients in cc" do
|
||||
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
|
||||
user_two = insert(:user)
|
||||
user_three = insert(:user)
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns sharedInbox for messages involving multiple recipients in total" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
shared_inbox: "http://example.com/inbox",
|
||||
inbox: "http://example.com/personal-inbox"
|
||||
})
|
||||
|
||||
user_two = insert(:user)
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns inbox for messages involving single recipients in total" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
shared_inbox: "http://example.com/inbox",
|
||||
inbox: "http://example.com/personal-inbox"
|
||||
})
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"to" => [user.ap_id], "cc" => []}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
|
||||
end
|
||||
end
|
||||
|
||||
describe "publish_one/1" do
|
||||
test "publish to url with with different ports" do
|
||||
inbox80 = "http://42.site/users/nick1/inbox"
|
||||
inbox42 = "http://42.site:42/users/nick1/inbox"
|
||||
|
||||
mock(fn
|
||||
%{method: :post, url: "http://42.site:42/users/nick1/inbox"} ->
|
||||
{:ok, %Tesla.Env{status: 200, body: "port 42"}}
|
||||
|
||||
%{method: :post, url: "http://42.site/users/nick1/inbox"} ->
|
||||
{:ok, %Tesla.Env{status: 200, body: "port 80"}}
|
||||
end)
|
||||
|
||||
actor = insert(:user)
|
||||
|
||||
assert {:ok, %{body: "port 42"}} =
|
||||
Publisher.publish_one(%{
|
||||
inbox: inbox42,
|
||||
json: "{}",
|
||||
actor: actor,
|
||||
id: 1,
|
||||
unreachable_since: true
|
||||
})
|
||||
|
||||
assert {:ok, %{body: "port 80"}} =
|
||||
Publisher.publish_one(%{
|
||||
inbox: inbox80,
|
||||
json: "{}",
|
||||
actor: actor,
|
||||
id: 1,
|
||||
unreachable_since: true
|
||||
})
|
||||
end
|
||||
|
||||
test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://200.site/users/nick1/inbox"
|
||||
|
||||
assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
|
||||
assert called(Instances.set_reachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://200.site/users/nick1/inbox"
|
||||
|
||||
assert {:ok, _} =
|
||||
Publisher.publish_one(%{
|
||||
inbox: inbox,
|
||||
json: "{}",
|
||||
actor: actor,
|
||||
id: 1,
|
||||
unreachable_since: NaiveDateTime.utc_now()
|
||||
})
|
||||
|
||||
assert called(Instances.set_reachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://200.site/users/nick1/inbox"
|
||||
|
||||
assert {:ok, _} =
|
||||
Publisher.publish_one(%{
|
||||
inbox: inbox,
|
||||
json: "{}",
|
||||
actor: actor,
|
||||
id: 1,
|
||||
unreachable_since: nil
|
||||
})
|
||||
|
||||
refute called(Instances.set_reachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://404.site/users/nick1/inbox"
|
||||
|
||||
assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
|
||||
|
||||
assert called(Instances.set_unreachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://connrefused.site/users/nick1/inbox"
|
||||
|
||||
assert capture_log(fn ->
|
||||
assert {:error, _} =
|
||||
Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
|
||||
end) =~ "connrefused"
|
||||
|
||||
assert called(Instances.set_unreachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://200.site/users/nick1/inbox"
|
||||
|
||||
assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
|
||||
|
||||
refute called(Instances.set_unreachable(inbox))
|
||||
end
|
||||
|
||||
test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
[] do
|
||||
actor = insert(:user)
|
||||
inbox = "http://connrefused.site/users/nick1/inbox"
|
||||
|
||||
assert capture_log(fn ->
|
||||
assert {:error, _} =
|
||||
Publisher.publish_one(%{
|
||||
inbox: inbox,
|
||||
json: "{}",
|
||||
actor: actor,
|
||||
id: 1,
|
||||
unreachable_since: NaiveDateTime.utc_now()
|
||||
})
|
||||
end) =~ "connrefused"
|
||||
|
||||
refute called(Instances.set_unreachable(inbox))
|
||||
end
|
||||
end
|
||||
|
||||
describe "publish/2" do
|
||||
test_with_mock "publishes an activity with BCC to all relevant peers.",
|
||||
Pleroma.Web.Federator.Publisher,
|
||||
[:passthrough],
|
||||
[] do
|
||||
follower =
|
||||
insert(:user, %{
|
||||
local: false,
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
ap_enabled: true
|
||||
})
|
||||
|
||||
actor = insert(:user, follower_address: follower.ap_id)
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, _follower_one} = Pleroma.User.follow(follower, actor)
|
||||
actor = refresh_record(actor)
|
||||
|
||||
note_activity =
|
||||
insert(:note_activity,
|
||||
recipients: [follower.ap_id],
|
||||
data_attrs: %{"bcc" => [user.ap_id]}
|
||||
)
|
||||
|
||||
res = Publisher.publish(actor, note_activity)
|
||||
assert res == :ok
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
actor_id: actor.id,
|
||||
id: note_activity.data["id"]
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.",
|
||||
Pleroma.Web.Federator.Publisher,
|
||||
[:passthrough],
|
||||
[] do
|
||||
fetcher =
|
||||
insert(:user,
|
||||
local: false,
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
ap_enabled: true
|
||||
)
|
||||
|
||||
another_fetcher =
|
||||
insert(:user,
|
||||
local: false,
|
||||
inbox: "https://domain2.com/users/nick1/inbox",
|
||||
ap_enabled: true
|
||||
)
|
||||
|
||||
actor = insert(:user)
|
||||
|
||||
note_activity = insert(:note_activity, user: actor)
|
||||
object = Object.normalize(note_activity)
|
||||
|
||||
activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url())
|
||||
object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
|
||||
|
||||
build_conn()
|
||||
|> put_req_header("accept", "application/activity+json")
|
||||
|> assign(:user, fetcher)
|
||||
|> get(object_path)
|
||||
|> json_response(200)
|
||||
|
||||
build_conn()
|
||||
|> put_req_header("accept", "application/activity+json")
|
||||
|> assign(:user, another_fetcher)
|
||||
|> get(activity_path)
|
||||
|> json_response(200)
|
||||
|
||||
{:ok, delete} = CommonAPI.delete(note_activity.id, actor)
|
||||
|
||||
res = Publisher.publish(actor, delete)
|
||||
assert res == :ok
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
actor_id: actor.id,
|
||||
id: delete.data["id"]
|
||||
})
|
||||
)
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
|
||||
inbox: "https://domain2.com/users/nick1/inbox",
|
||||
actor_id: actor.id,
|
||||
id: delete.data["id"]
|
||||
})
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
# 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.RelayTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import ExUnit.CaptureLog
|
||||
import Pleroma.Factory
|
||||
import Mock
|
||||
|
||||
test "gets an actor for the relay" do
|
||||
user = Relay.get_actor()
|
||||
assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
end
|
||||
|
||||
test "relay actor is invisible" do
|
||||
user = Relay.get_actor()
|
||||
assert User.invisible?(user)
|
||||
end
|
||||
|
||||
describe "follow/1" do
|
||||
test "returns errors when user not found" do
|
||||
assert capture_log(fn ->
|
||||
{:error, _} = Relay.follow("test-ap-id")
|
||||
end) =~ "Could not decode user at fetch"
|
||||
end
|
||||
|
||||
test "returns activity" do
|
||||
user = insert(:user)
|
||||
service_actor = Relay.get_actor()
|
||||
assert {:ok, %Activity{} = activity} = Relay.follow(user.ap_id)
|
||||
assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
assert user.ap_id in activity.recipients
|
||||
assert activity.data["type"] == "Follow"
|
||||
assert activity.data["actor"] == service_actor.ap_id
|
||||
assert activity.data["object"] == user.ap_id
|
||||
end
|
||||
end
|
||||
|
||||
describe "unfollow/1" do
|
||||
test "returns errors when user not found" do
|
||||
assert capture_log(fn ->
|
||||
{:error, _} = Relay.unfollow("test-ap-id")
|
||||
end) =~ "Could not decode user at fetch"
|
||||
end
|
||||
|
||||
test "returns activity" do
|
||||
user = insert(:user)
|
||||
service_actor = Relay.get_actor()
|
||||
CommonAPI.follow(service_actor, user)
|
||||
assert "#{user.ap_id}/followers" in User.following(service_actor)
|
||||
assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id)
|
||||
assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
assert user.ap_id in activity.recipients
|
||||
assert activity.data["type"] == "Undo"
|
||||
assert activity.data["actor"] == service_actor.ap_id
|
||||
assert activity.data["to"] == [user.ap_id]
|
||||
refute "#{user.ap_id}/followers" in User.following(service_actor)
|
||||
end
|
||||
|
||||
test "force unfollow when target service is dead" do
|
||||
user = insert(:user)
|
||||
user_ap_id = user.ap_id
|
||||
user_id = user.id
|
||||
|
||||
Tesla.Mock.mock(fn %{method: :get, url: ^user_ap_id} ->
|
||||
%Tesla.Env{status: 404}
|
||||
end)
|
||||
|
||||
service_actor = Relay.get_actor()
|
||||
CommonAPI.follow(service_actor, user)
|
||||
assert "#{user.ap_id}/followers" in User.following(service_actor)
|
||||
|
||||
assert Pleroma.Repo.get_by(
|
||||
Pleroma.FollowingRelationship,
|
||||
follower_id: service_actor.id,
|
||||
following_id: user_id
|
||||
)
|
||||
|
||||
Pleroma.Repo.delete(user)
|
||||
Cachex.clear(:user_cache)
|
||||
|
||||
assert {:ok, %Activity{} = activity} = Relay.unfollow(user_ap_id, %{force: true})
|
||||
|
||||
assert refresh_record(service_actor).following_count == 0
|
||||
|
||||
refute Pleroma.Repo.get_by(
|
||||
Pleroma.FollowingRelationship,
|
||||
follower_id: service_actor.id,
|
||||
following_id: user_id
|
||||
)
|
||||
|
||||
assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
assert user.ap_id in activity.recipients
|
||||
assert activity.data["type"] == "Undo"
|
||||
assert activity.data["actor"] == service_actor.ap_id
|
||||
assert activity.data["to"] == [user_ap_id]
|
||||
refute "#{user.ap_id}/followers" in User.following(service_actor)
|
||||
end
|
||||
end
|
||||
|
||||
describe "publish/1" do
|
||||
setup do: clear_config([:instance, :federating])
|
||||
|
||||
test "returns error when activity not `Create` type" do
|
||||
activity = insert(:like_activity)
|
||||
assert Relay.publish(activity) == {:error, "Not implemented"}
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "returns error when activity not public" do
|
||||
activity = insert(:direct_note_activity)
|
||||
assert Relay.publish(activity) == {:error, false}
|
||||
end
|
||||
|
||||
test "returns error when object is unknown" do
|
||||
activity =
|
||||
insert(:note_activity,
|
||||
data: %{
|
||||
"type" => "Create",
|
||||
"object" => "http://mastodon.example.org/eee/99541947525187367"
|
||||
}
|
||||
)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: :get, url: "http://mastodon.example.org/eee/99541947525187367"} ->
|
||||
%Tesla.Env{status: 500, body: ""}
|
||||
end)
|
||||
|
||||
assert capture_log(fn ->
|
||||
assert Relay.publish(activity) == {:error, false}
|
||||
end) =~ "[error] error: false"
|
||||
end
|
||||
|
||||
test_with_mock "returns announce activity and publish to federate",
|
||||
Pleroma.Web.Federator,
|
||||
[:passthrough],
|
||||
[] do
|
||||
clear_config([:instance, :federating], true)
|
||||
service_actor = Relay.get_actor()
|
||||
note = insert(:note_activity)
|
||||
assert {:ok, %Activity{} = activity} = Relay.publish(note)
|
||||
assert activity.data["type"] == "Announce"
|
||||
assert activity.data["actor"] == service_actor.ap_id
|
||||
assert activity.data["to"] == [service_actor.follower_address]
|
||||
assert called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
|
||||
test_with_mock "returns announce activity and not publish to federate",
|
||||
Pleroma.Web.Federator,
|
||||
[:passthrough],
|
||||
[] do
|
||||
clear_config([:instance, :federating], false)
|
||||
service_actor = Relay.get_actor()
|
||||
note = insert(:note_activity)
|
||||
assert {:ok, %Activity{} = activity} = Relay.publish(note)
|
||||
assert activity.data["type"] == "Announce"
|
||||
assert activity.data["actor"] == service_actor.ap_id
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,639 +0,0 @@
|
|||
# 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.SideEffectsTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Chat
|
||||
alias Pleroma.Chat.MessageReference
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.Tests.ObanHelpers
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Builder
|
||||
alias Pleroma.Web.ActivityPub.SideEffects
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import ExUnit.CaptureLog
|
||||
import Mock
|
||||
import Pleroma.Factory
|
||||
|
||||
describe "handle_after_transaction" do
|
||||
test "it streams out notifications and streams" do
|
||||
author = insert(:user, local: true)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
{:ok, _create_activity, meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
assert [notification] = meta[:notifications]
|
||||
|
||||
with_mocks([
|
||||
{
|
||||
Pleroma.Web.Streamer,
|
||||
[],
|
||||
[
|
||||
stream: fn _, _ -> nil end
|
||||
]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Push,
|
||||
[],
|
||||
[
|
||||
send: fn _ -> nil end
|
||||
]
|
||||
}
|
||||
]) do
|
||||
SideEffects.handle_after_transaction(meta)
|
||||
|
||||
assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
|
||||
assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
|
||||
assert called(Pleroma.Web.Push.send(notification))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "blocking users" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
blocked = insert(:user)
|
||||
User.follow(blocked, user)
|
||||
User.follow(user, blocked)
|
||||
|
||||
{:ok, block_data, []} = Builder.block(user, blocked)
|
||||
{:ok, block, _meta} = ActivityPub.persist(block_data, local: true)
|
||||
|
||||
%{user: user, blocked: blocked, block: block}
|
||||
end
|
||||
|
||||
test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do
|
||||
assert User.following?(user, blocked)
|
||||
assert User.following?(blocked, user)
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(block)
|
||||
|
||||
refute User.following?(user, blocked)
|
||||
refute User.following?(blocked, user)
|
||||
assert User.blocks?(user, blocked)
|
||||
end
|
||||
|
||||
test "it blocks but does not unfollow if the relevant setting is set", %{
|
||||
user: user,
|
||||
blocked: blocked,
|
||||
block: block
|
||||
} do
|
||||
clear_config([:activitypub, :unfollow_blocked], false)
|
||||
assert User.following?(user, blocked)
|
||||
assert User.following?(blocked, user)
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(block)
|
||||
|
||||
refute User.following?(user, blocked)
|
||||
assert User.following?(blocked, user)
|
||||
assert User.blocks?(user, blocked)
|
||||
end
|
||||
end
|
||||
|
||||
describe "update users" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
{:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"})
|
||||
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
|
||||
|
||||
%{user: user, update_data: update_data, update: update}
|
||||
end
|
||||
|
||||
test "it updates the user", %{user: user, update: update} do
|
||||
{:ok, _, _} = SideEffects.handle(update)
|
||||
user = User.get_by_id(user.id)
|
||||
assert user.name == "new name!"
|
||||
end
|
||||
|
||||
test "it uses a given changeset to update", %{user: user, update: update} do
|
||||
changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
|
||||
|
||||
assert user.default_scope == "public"
|
||||
{:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
|
||||
user = User.get_by_id(user.id)
|
||||
assert user.default_scope == "direct"
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete objects" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
|
||||
{:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
|
||||
{:ok, favorite} = CommonAPI.favorite(user, post.id)
|
||||
object = Object.normalize(post)
|
||||
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
|
||||
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
|
||||
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
|
||||
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
|
||||
|
||||
%{
|
||||
user: user,
|
||||
delete: delete,
|
||||
post: post,
|
||||
object: object,
|
||||
delete_user: delete_user,
|
||||
op: op,
|
||||
favorite: favorite
|
||||
}
|
||||
end
|
||||
|
||||
test "it handles object deletions", %{
|
||||
delete: delete,
|
||||
post: post,
|
||||
object: object,
|
||||
user: user,
|
||||
op: op,
|
||||
favorite: favorite
|
||||
} do
|
||||
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
|
||||
stream_out: fn _ -> nil end,
|
||||
stream_out_participations: fn _, _ -> nil end do
|
||||
{:ok, delete, _} = SideEffects.handle(delete)
|
||||
user = User.get_cached_by_ap_id(object.data["actor"])
|
||||
|
||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
|
||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
|
||||
end
|
||||
|
||||
object = Object.get_by_id(object.id)
|
||||
assert object.data["type"] == "Tombstone"
|
||||
refute Activity.get_by_id(post.id)
|
||||
refute Activity.get_by_id(favorite.id)
|
||||
|
||||
user = User.get_by_id(user.id)
|
||||
assert user.note_count == 0
|
||||
|
||||
object = Object.normalize(op.data["object"], false)
|
||||
|
||||
assert object.data["repliesCount"] == 0
|
||||
end
|
||||
|
||||
test "it handles object deletions when the object itself has been pruned", %{
|
||||
delete: delete,
|
||||
post: post,
|
||||
object: object,
|
||||
user: user,
|
||||
op: op
|
||||
} do
|
||||
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
|
||||
stream_out: fn _ -> nil end,
|
||||
stream_out_participations: fn _, _ -> nil end do
|
||||
{:ok, delete, _} = SideEffects.handle(delete)
|
||||
user = User.get_cached_by_ap_id(object.data["actor"])
|
||||
|
||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
|
||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
|
||||
end
|
||||
|
||||
object = Object.get_by_id(object.id)
|
||||
assert object.data["type"] == "Tombstone"
|
||||
refute Activity.get_by_id(post.id)
|
||||
|
||||
user = User.get_by_id(user.id)
|
||||
assert user.note_count == 0
|
||||
|
||||
object = Object.normalize(op.data["object"], false)
|
||||
|
||||
assert object.data["repliesCount"] == 0
|
||||
end
|
||||
|
||||
test "it handles user deletions", %{delete_user: delete, user: user} do
|
||||
{:ok, _delete, _} = SideEffects.handle(delete)
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
assert User.get_cached_by_ap_id(user.ap_id).deactivated
|
||||
end
|
||||
|
||||
test "it logs issues with objects deletion", %{
|
||||
delete: delete,
|
||||
object: object
|
||||
} do
|
||||
{:ok, object} =
|
||||
object
|
||||
|> Object.change(%{data: Map.delete(object.data, "actor")})
|
||||
|> Repo.update()
|
||||
|
||||
Object.invalid_object_cache(object)
|
||||
|
||||
assert capture_log(fn ->
|
||||
{:error, :no_object_actor} = SideEffects.handle(delete)
|
||||
end) =~ "object doesn't have an actor"
|
||||
end
|
||||
end
|
||||
|
||||
describe "EmojiReact objects" do
|
||||
setup do
|
||||
poster = insert(:user)
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
|
||||
|
||||
{:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
|
||||
{:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
|
||||
|
||||
%{emoji_react: emoji_react, user: user, poster: poster}
|
||||
end
|
||||
|
||||
test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
|
||||
{:ok, emoji_react, _} = SideEffects.handle(emoji_react)
|
||||
object = Object.get_by_ap_id(emoji_react.data["object"])
|
||||
|
||||
assert object.data["reaction_count"] == 1
|
||||
assert ["👌", [user.ap_id]] in object.data["reactions"]
|
||||
end
|
||||
|
||||
test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
|
||||
{:ok, emoji_react, _} = SideEffects.handle(emoji_react)
|
||||
assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete users with confirmation pending" do
|
||||
setup do
|
||||
user = insert(:user, confirmation_pending: true)
|
||||
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
|
||||
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
|
||||
{:ok, delete: delete_user, user: user}
|
||||
end
|
||||
|
||||
test "when activation is not required", %{delete: delete, user: user} do
|
||||
clear_config([:instance, :account_activation_required], false)
|
||||
{:ok, _, _} = SideEffects.handle(delete)
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
assert User.get_cached_by_id(user.id).deactivated
|
||||
end
|
||||
|
||||
test "when activation is required", %{delete: delete, user: user} do
|
||||
clear_config([:instance, :account_activation_required], true)
|
||||
{:ok, _, _} = SideEffects.handle(delete)
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
refute User.get_cached_by_id(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Undo objects" do
|
||||
setup do
|
||||
poster = insert(:user)
|
||||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
|
||||
{:ok, like} = CommonAPI.favorite(user, post.id)
|
||||
{:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
|
||||
{:ok, announce} = CommonAPI.repeat(post.id, user)
|
||||
{:ok, block} = CommonAPI.block(user, poster)
|
||||
|
||||
{:ok, undo_data, _meta} = Builder.undo(user, like)
|
||||
{:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
|
||||
|
||||
{:ok, undo_data, _meta} = Builder.undo(user, reaction)
|
||||
{:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
|
||||
|
||||
{:ok, undo_data, _meta} = Builder.undo(user, announce)
|
||||
{:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
|
||||
|
||||
{:ok, undo_data, _meta} = Builder.undo(user, block)
|
||||
{:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
|
||||
|
||||
%{
|
||||
like_undo: like_undo,
|
||||
post: post,
|
||||
like: like,
|
||||
reaction_undo: reaction_undo,
|
||||
reaction: reaction,
|
||||
announce_undo: announce_undo,
|
||||
announce: announce,
|
||||
block_undo: block_undo,
|
||||
block: block,
|
||||
poster: poster,
|
||||
user: user
|
||||
}
|
||||
end
|
||||
|
||||
test "deletes the original block", %{
|
||||
block_undo: block_undo,
|
||||
block: block
|
||||
} do
|
||||
{:ok, _block_undo, _meta} = SideEffects.handle(block_undo)
|
||||
|
||||
refute Activity.get_by_id(block.id)
|
||||
end
|
||||
|
||||
test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
|
||||
blocker = User.get_by_ap_id(block.data["actor"])
|
||||
blocked = User.get_by_ap_id(block.data["object"])
|
||||
|
||||
{:ok, _block_undo, _} = SideEffects.handle(block_undo)
|
||||
refute User.blocks?(blocker, blocked)
|
||||
end
|
||||
|
||||
test "an announce undo removes the announce from the object", %{
|
||||
announce_undo: announce_undo,
|
||||
post: post
|
||||
} do
|
||||
{:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
|
||||
|
||||
object = Object.get_by_ap_id(post.data["object"])
|
||||
|
||||
assert object.data["announcement_count"] == 0
|
||||
assert object.data["announcements"] == []
|
||||
end
|
||||
|
||||
test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
|
||||
{:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
|
||||
refute Activity.get_by_id(announce.id)
|
||||
end
|
||||
|
||||
test "a reaction undo removes the reaction from the object", %{
|
||||
reaction_undo: reaction_undo,
|
||||
post: post
|
||||
} do
|
||||
{:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
|
||||
|
||||
object = Object.get_by_ap_id(post.data["object"])
|
||||
|
||||
assert object.data["reaction_count"] == 0
|
||||
assert object.data["reactions"] == []
|
||||
end
|
||||
|
||||
test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
|
||||
{:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
|
||||
refute Activity.get_by_id(reaction.id)
|
||||
end
|
||||
|
||||
test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
|
||||
{:ok, _like_undo, _} = SideEffects.handle(like_undo)
|
||||
|
||||
object = Object.get_by_ap_id(post.data["object"])
|
||||
|
||||
assert object.data["like_count"] == 0
|
||||
assert object.data["likes"] == []
|
||||
end
|
||||
|
||||
test "deletes the original like", %{like_undo: like_undo, like: like} do
|
||||
{:ok, _like_undo, _} = SideEffects.handle(like_undo)
|
||||
refute Activity.get_by_id(like.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "like objects" do
|
||||
setup do
|
||||
poster = insert(:user)
|
||||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
|
||||
|
||||
{:ok, like_data, _meta} = Builder.like(user, post.object)
|
||||
{:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
|
||||
|
||||
%{like: like, user: user, poster: poster}
|
||||
end
|
||||
|
||||
test "add the like to the original object", %{like: like, user: user} do
|
||||
{:ok, like, _} = SideEffects.handle(like)
|
||||
object = Object.get_by_ap_id(like.data["object"])
|
||||
assert object.data["like_count"] == 1
|
||||
assert user.ap_id in object.data["likes"]
|
||||
end
|
||||
|
||||
test "creates a notification", %{like: like, poster: poster} do
|
||||
{:ok, like, _} = SideEffects.handle(like)
|
||||
assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "creation of ChatMessages" do
|
||||
test "notifies the recipient" do
|
||||
author = insert(:user, local: false)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
{:ok, _create_activity, _meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
|
||||
end
|
||||
|
||||
test "it streams the created ChatMessage" do
|
||||
author = insert(:user, local: true)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
{:ok, _create_activity, meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
assert [_, _] = meta[:streamables]
|
||||
end
|
||||
|
||||
test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do
|
||||
author = insert(:user, local: true)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
with_mocks([
|
||||
{
|
||||
Pleroma.Web.Streamer,
|
||||
[],
|
||||
[
|
||||
stream: fn _, _ -> nil end
|
||||
]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Push,
|
||||
[],
|
||||
[
|
||||
send: fn _ -> nil end
|
||||
]
|
||||
}
|
||||
]) do
|
||||
{:ok, _create_activity, meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
# The notification gets created
|
||||
assert [notification] = meta[:notifications]
|
||||
assert notification.activity_id == create_activity.id
|
||||
|
||||
# But it is not sent out
|
||||
refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
|
||||
refute called(Pleroma.Web.Push.send(notification))
|
||||
|
||||
# Same for the user chat stream
|
||||
assert [{topics, _}, _] = meta[:streamables]
|
||||
assert topics == ["user", "user:pleroma_chat"]
|
||||
refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
|
||||
|
||||
chat = Chat.get(author.id, recipient.ap_id)
|
||||
|
||||
[cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
|
||||
|
||||
assert cm_ref.object.data["content"] == "hey"
|
||||
assert cm_ref.unread == false
|
||||
|
||||
chat = Chat.get(recipient.id, author.ap_id)
|
||||
|
||||
[cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
|
||||
|
||||
assert cm_ref.object.data["content"] == "hey"
|
||||
assert cm_ref.unread == true
|
||||
end
|
||||
end
|
||||
|
||||
test "it creates a Chat for the local users and bumps the unread count" do
|
||||
author = insert(:user, local: false)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
{:ok, _create_activity, _meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
# An object is created
|
||||
assert Object.get_by_ap_id(chat_message_data["id"])
|
||||
|
||||
# The remote user won't get a chat
|
||||
chat = Chat.get(author.id, recipient.ap_id)
|
||||
refute chat
|
||||
|
||||
# The local user will get a chat
|
||||
chat = Chat.get(recipient.id, author.ap_id)
|
||||
assert chat
|
||||
|
||||
author = insert(:user, local: true)
|
||||
recipient = insert(:user, local: true)
|
||||
|
||||
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
|
||||
|
||||
{:ok, create_activity_data, _meta} =
|
||||
Builder.create(author, chat_message_data["id"], [recipient.ap_id])
|
||||
|
||||
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
|
||||
|
||||
{:ok, _create_activity, _meta} =
|
||||
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
|
||||
|
||||
# Both users are local and get the chat
|
||||
chat = Chat.get(author.id, recipient.ap_id)
|
||||
assert chat
|
||||
|
||||
chat = Chat.get(recipient.id, author.ap_id)
|
||||
assert chat
|
||||
end
|
||||
end
|
||||
|
||||
describe "announce objects" do
|
||||
setup do
|
||||
poster = insert(:user)
|
||||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
|
||||
{:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
|
||||
|
||||
{:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
|
||||
|
||||
{:ok, private_announce_data, _meta} =
|
||||
Builder.announce(user, private_post.object, public: false)
|
||||
|
||||
{:ok, relay_announce_data, _meta} =
|
||||
Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
|
||||
|
||||
{:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
|
||||
{:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
|
||||
{:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
|
||||
|
||||
%{
|
||||
announce: announce,
|
||||
user: user,
|
||||
poster: poster,
|
||||
private_announce: private_announce,
|
||||
relay_announce: relay_announce
|
||||
}
|
||||
end
|
||||
|
||||
test "adds the announce to the original object", %{announce: announce, user: user} do
|
||||
{:ok, announce, _} = SideEffects.handle(announce)
|
||||
object = Object.get_by_ap_id(announce.data["object"])
|
||||
assert object.data["announcement_count"] == 1
|
||||
assert user.ap_id in object.data["announcements"]
|
||||
end
|
||||
|
||||
test "does not add the announce to the original object if the actor is a service actor", %{
|
||||
relay_announce: announce
|
||||
} do
|
||||
{:ok, announce, _} = SideEffects.handle(announce)
|
||||
object = Object.get_by_ap_id(announce.data["object"])
|
||||
assert object.data["announcement_count"] == nil
|
||||
end
|
||||
|
||||
test "creates a notification", %{announce: announce, poster: poster} do
|
||||
{:ok, announce, _} = SideEffects.handle(announce)
|
||||
assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
|
||||
end
|
||||
|
||||
test "it streams out the announce", %{announce: announce} do
|
||||
with_mocks([
|
||||
{
|
||||
Pleroma.Web.Streamer,
|
||||
[],
|
||||
[
|
||||
stream: fn _, _ -> nil end
|
||||
]
|
||||
},
|
||||
{
|
||||
Pleroma.Web.Push,
|
||||
[],
|
||||
[
|
||||
send: fn _ -> nil end
|
||||
]
|
||||
}
|
||||
]) do
|
||||
{:ok, announce, _} = SideEffects.handle(announce)
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce)
|
||||
)
|
||||
|
||||
assert called(Pleroma.Web.Push.send(:_))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
# 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.AnnounceHandlingTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "it works for incoming honk announces" do
|
||||
user = insert(:user, ap_id: "https://honktest/u/test", local: false)
|
||||
other_user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
|
||||
|
||||
announce = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"actor" => "https://honktest/u/test",
|
||||
"id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
|
||||
"object" => post.data["object"],
|
||||
"published" => "2019-06-25T19:33:58Z",
|
||||
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type" => "Announce"
|
||||
}
|
||||
|
||||
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
|
||||
|
||||
object = Object.get_by_ap_id(post.data["object"])
|
||||
|
||||
assert length(object.data["announcements"]) == 1
|
||||
assert user.ap_id in object.data["announcements"]
|
||||
end
|
||||
|
||||
test "it works for incoming announces with actor being inlined (kroeg)" do
|
||||
data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
|
||||
|
||||
_user = insert(:user, local: false, ap_id: data["actor"]["id"])
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, post} = CommonAPI.post(other_user, %{status: "kroegeroeg"})
|
||||
|
||||
data =
|
||||
data
|
||||
|> put_in(["object", "id"], post.data["object"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "https://puckipedia.com/"
|
||||
end
|
||||
|
||||
test "it works for incoming announces, fetching the announced object" do
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-announce.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367")
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: :get} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
|
||||
end)
|
||||
|
||||
_user = insert(:user, local: false, ap_id: data["actor"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Announce"
|
||||
|
||||
assert data["id"] ==
|
||||
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
|
||||
|
||||
assert data["object"] ==
|
||||
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
|
||||
|
||||
assert(Activity.get_create_by_object_ap_id(data["object"]))
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "it works for incoming announces with an existing activity" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-announce.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_user = insert(:user, local: false, ap_id: data["actor"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Announce"
|
||||
|
||||
assert data["id"] ==
|
||||
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
|
||||
|
||||
assert data["object"] == activity.data["object"]
|
||||
|
||||
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
|
||||
end
|
||||
|
||||
# Ignore inlined activities for now
|
||||
@tag skip: true
|
||||
test "it works for incoming announces with an inlined activity" do
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-announce-private.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
_user =
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: data["actor"],
|
||||
follower_address: data["actor"] <> "/followers"
|
||||
)
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Announce"
|
||||
|
||||
assert data["id"] ==
|
||||
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
|
||||
|
||||
object = Object.normalize(data["object"])
|
||||
|
||||
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
|
||||
assert object.data["content"] == "this is a private toot"
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "it rejects incoming announces with an inlined activity from another origin" do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
|
||||
end)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/bogus-mastodon-announce.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
_user = insert(:user, local: false, ap_id: data["actor"])
|
||||
|
||||
assert {:error, e} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it does not clobber the addressing on announce activities" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-announce.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", Object.normalize(activity).data["id"])
|
||||
|> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
|
||||
|> Map.put("cc", [])
|
||||
|
||||
_user =
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: data["actor"],
|
||||
follower_address: "http://mastodon.example.org/users/admin/followers"
|
||||
)
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
|
||||
end
|
||||
end
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
# 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.ChatMessageTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Chat
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
describe "handle_incoming" do
|
||||
test "handles chonks with attachment" do
|
||||
data = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"actor" => "https://honk.tedunangst.com/u/tedu",
|
||||
"id" => "https://honk.tedunangst.com/u/tedu/honk/x6gt8X8PcyGkQcXxzg1T",
|
||||
"object" => %{
|
||||
"attachment" => [
|
||||
%{
|
||||
"mediaType" => "image/jpeg",
|
||||
"name" => "298p3RG7j27tfsZ9RQ.jpg",
|
||||
"summary" => "298p3RG7j27tfsZ9RQ.jpg",
|
||||
"type" => "Document",
|
||||
"url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg"
|
||||
}
|
||||
],
|
||||
"attributedTo" => "https://honk.tedunangst.com/u/tedu",
|
||||
"content" => "",
|
||||
"id" => "https://honk.tedunangst.com/u/tedu/chonk/26L4wl5yCbn4dr4y1b",
|
||||
"published" => "2020-05-18T01:13:03Z",
|
||||
"to" => [
|
||||
"https://dontbulling.me/users/lain"
|
||||
],
|
||||
"type" => "ChatMessage"
|
||||
},
|
||||
"published" => "2020-05-18T01:13:03Z",
|
||||
"to" => [
|
||||
"https://dontbulling.me/users/lain"
|
||||
],
|
||||
"type" => "Create"
|
||||
}
|
||||
|
||||
_user = insert(:user, ap_id: data["actor"])
|
||||
_user = insert(:user, ap_id: hd(data["to"]))
|
||||
|
||||
assert {:ok, _activity} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it rejects messages that don't contain content" do
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
object =
|
||||
data["object"]
|
||||
|> Map.delete("content")
|
||||
|
||||
data =
|
||||
data
|
||||
|> Map.put("object", object)
|
||||
|
||||
_author =
|
||||
insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
|
||||
|
||||
_recipient =
|
||||
insert(:user,
|
||||
ap_id: List.first(data["to"]),
|
||||
local: true,
|
||||
last_refreshed_at: DateTime.utc_now()
|
||||
)
|
||||
|
||||
{:error, _} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it rejects messages that don't concern local users" do
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
_author =
|
||||
insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
|
||||
|
||||
_recipient =
|
||||
insert(:user,
|
||||
ap_id: List.first(data["to"]),
|
||||
local: false,
|
||||
last_refreshed_at: DateTime.utc_now()
|
||||
)
|
||||
|
||||
{:error, _} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it rejects messages where the `to` field of activity and object don't match" do
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
author = insert(:user, ap_id: data["actor"])
|
||||
_recipient = insert(:user, ap_id: List.first(data["to"]))
|
||||
|
||||
data =
|
||||
data
|
||||
|> Map.put("to", author.ap_id)
|
||||
|
||||
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
||||
refute Object.get_by_ap_id(data["object"]["id"])
|
||||
end
|
||||
|
||||
test "it fetches the actor if they aren't in our system" do
|
||||
Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("actor", "http://mastodon.example.org/users/admin")
|
||||
|> put_in(["object", "actor"], "http://mastodon.example.org/users/admin")
|
||||
|
||||
_recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
|
||||
|
||||
{:ok, %Activity{} = _activity} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it doesn't work for deactivated users" do
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
_author =
|
||||
insert(:user,
|
||||
ap_id: data["actor"],
|
||||
local: false,
|
||||
last_refreshed_at: DateTime.utc_now(),
|
||||
deactivated: true
|
||||
)
|
||||
|
||||
_recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
|
||||
|
||||
assert {:error, _} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
test "it inserts it and creates a chat" do
|
||||
data =
|
||||
File.read!("test/fixtures/create-chat-message.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
author =
|
||||
insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
|
||||
|
||||
recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
|
||||
|
||||
{:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data)
|
||||
assert activity.local == false
|
||||
|
||||
assert activity.actor == author.ap_id
|
||||
assert activity.recipients == [recipient.ap_id, author.ap_id]
|
||||
|
||||
%Object{} = object = Object.get_by_ap_id(activity.data["object"])
|
||||
|
||||
assert object
|
||||
assert object.data["content"] == "You expected a cute girl? Too bad. alert('XSS')"
|
||||
assert match?(%{"firefox" => _}, object.data["emoji"])
|
||||
|
||||
refute Chat.get(author.id, recipient.ap_id)
|
||||
assert Chat.get(recipient.id, author.ap_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
# 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.DeleteHandlingTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Tests.ObanHelpers
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
test "it works for incoming deletes" do
|
||||
activity = insert(:note_activity)
|
||||
deleting_user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-delete.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("actor", deleting_user.ap_id)
|
||||
|> put_in(["object", "id"], activity.data["object"])
|
||||
|
||||
{:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
|
||||
Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert id == data["id"]
|
||||
|
||||
# We delete the Create activity because we base our timelines on it.
|
||||
# This should be changed after we unify objects and activities
|
||||
refute Activity.get_by_id(activity.id)
|
||||
assert actor == deleting_user.ap_id
|
||||
|
||||
# Objects are replaced by a tombstone object.
|
||||
object = Object.normalize(activity.data["object"])
|
||||
assert object.data["type"] == "Tombstone"
|
||||
end
|
||||
|
||||
test "it works for incoming when the object has been pruned" do
|
||||
activity = insert(:note_activity)
|
||||
|
||||
{:ok, object} =
|
||||
Object.normalize(activity.data["object"])
|
||||
|> Repo.delete()
|
||||
|
||||
Cachex.del(:object_cache, "object:#{object.data["id"]}")
|
||||
|
||||
deleting_user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-delete.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("actor", deleting_user.ap_id)
|
||||
|> put_in(["object", "id"], activity.data["object"])
|
||||
|
||||
{:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
|
||||
Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert id == data["id"]
|
||||
|
||||
# We delete the Create activity because we base our timelines on it.
|
||||
# This should be changed after we unify objects and activities
|
||||
refute Activity.get_by_id(activity.id)
|
||||
assert actor == deleting_user.ap_id
|
||||
end
|
||||
|
||||
test "it fails for incoming deletes with spoofed origin" do
|
||||
activity = insert(:note_activity)
|
||||
%{ap_id: ap_id} = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo")
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-delete.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("actor", ap_id)
|
||||
|> put_in(["object", "id"], activity.data["object"])
|
||||
|
||||
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "it works for incoming user deletes" do
|
||||
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-delete-user.json")
|
||||
|> Poison.decode!()
|
||||
|
||||
{:ok, _} = Transmogrifier.handle_incoming(data)
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
assert User.get_cached_by_ap_id(ap_id).deactivated
|
||||
end
|
||||
|
||||
test "it fails for incoming user deletes with spoofed origin" do
|
||||
%{ap_id: ap_id} = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-delete-user.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("actor", ap_id)
|
||||
|
||||
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
||||
|
||||
assert User.get_cached_by_ap_id(ap_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# 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.EmojiReactHandlingTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "it works for incoming emoji reactions" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user, local: false)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/emoji-reaction.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|> Map.put("actor", other_user.ap_id)
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == other_user.ap_id
|
||||
assert data["type"] == "EmojiReact"
|
||||
assert data["id"] == "http://mastodon.example.org/users/admin#reactions/2"
|
||||
assert data["object"] == activity.data["object"]
|
||||
assert data["content"] == "👌"
|
||||
|
||||
object = Object.get_by_ap_id(data["object"])
|
||||
|
||||
assert object.data["reaction_count"] == 1
|
||||
assert match?([["👌", _]], object.data["reactions"])
|
||||
end
|
||||
|
||||
test "it reject invalid emoji reactions" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user, local: false)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/emoji-reaction-too-long.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|> Map.put("actor", other_user.ap_id)
|
||||
|
||||
assert {:error, _} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/emoji-reaction-no-emoji.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|> Map.put("actor", other_user.ap_id)
|
||||
|
||||
assert {:error, _} = Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
# 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.FollowHandlingTest do
|
||||
use Pleroma.DataCase
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
|
||||
import Pleroma.Factory
|
||||
import Ecto.Query
|
||||
import Mock
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
describe "handle_incoming" do
|
||||
setup do: clear_config([:user, :deny_follow_blocked])
|
||||
|
||||
test "it works for osada follow request" do
|
||||
user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/osada-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "https://apfed.club/channel/indio"
|
||||
assert data["type"] == "Follow"
|
||||
assert data["id"] == "https://apfed.club/follow/9"
|
||||
|
||||
activity = Repo.get(Activity, activity.id)
|
||||
assert activity.data["state"] == "accept"
|
||||
assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
|
||||
end
|
||||
|
||||
test "it works for incoming follow requests" do
|
||||
user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Follow"
|
||||
assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
|
||||
|
||||
activity = Repo.get(Activity, activity.id)
|
||||
assert activity.data["state"] == "accept"
|
||||
assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
|
||||
|
||||
[notification] = Notification.for_user(user)
|
||||
assert notification.type == "follow"
|
||||
end
|
||||
|
||||
test "with locked accounts, it does create a Follow, but not an Accept" do
|
||||
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["state"] == "pending"
|
||||
|
||||
refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
|
||||
|
||||
accepts =
|
||||
from(
|
||||
a in Activity,
|
||||
where: fragment("?->>'type' = ?", a.data, "Accept")
|
||||
)
|
||||
|> Repo.all()
|
||||
|
||||
assert Enum.empty?(accepts)
|
||||
|
||||
[notification] = Notification.for_user(user)
|
||||
assert notification.type == "follow_request"
|
||||
end
|
||||
|
||||
test "it works for follow requests when you are already followed, creating a new accept activity" do
|
||||
# This is important because the remote might have the wrong idea about the
|
||||
# current follow status. This can lead to instance A thinking that x@A is
|
||||
# followed by y@B, but B thinks they are not. In this case, the follow can
|
||||
# never go through again because it will never get an Accept.
|
||||
user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
accepts =
|
||||
from(
|
||||
a in Activity,
|
||||
where: fragment("?->>'type' = ?", a.data, "Accept")
|
||||
)
|
||||
|> Repo.all()
|
||||
|
||||
assert length(accepts) == 1
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("id", String.replace(data["id"], "2", "3"))
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
accepts =
|
||||
from(
|
||||
a in Activity,
|
||||
where: fragment("?->>'type' = ?", a.data, "Accept")
|
||||
)
|
||||
|> Repo.all()
|
||||
|
||||
assert length(accepts) == 2
|
||||
end
|
||||
|
||||
test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
|
||||
Pleroma.Config.put([:user, :deny_follow_blocked], true)
|
||||
|
||||
user = insert(:user)
|
||||
{:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
|
||||
|
||||
{:ok, _user_relationship} = User.block(user, target)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
{:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
%Activity{} = activity = Activity.get_by_ap_id(id)
|
||||
|
||||
assert activity.data["state"] == "reject"
|
||||
end
|
||||
|
||||
test "it rejects incoming follow requests if the following errors for some reason" do
|
||||
user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
with_mock Pleroma.User, [:passthrough], follow: fn _, _, _ -> {:error, :testing} end do
|
||||
{:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
%Activity{} = activity = Activity.get_by_ap_id(id)
|
||||
|
||||
assert activity.data["state"] == "reject"
|
||||
end
|
||||
end
|
||||
|
||||
test "it works for incoming follow requests from hubzilla" do
|
||||
user = insert(:user)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/hubzilla-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|> Utils.normalize_params()
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
|
||||
assert data["type"] == "Follow"
|
||||
assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
|
||||
assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
|
||||
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
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
# 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.LikeHandlingTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "it works for incoming likes" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_actor = insert(:user, ap_id: data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
refute Enum.empty?(activity.recipients)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Like"
|
||||
assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
|
||||
assert data["object"] == activity.data["object"]
|
||||
end
|
||||
|
||||
test "it works for incoming misskey likes, turning them into EmojiReacts" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/misskey-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_actor = insert(:user, ap_id: data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: activity_data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert activity_data["actor"] == data["actor"]
|
||||
assert activity_data["type"] == "EmojiReact"
|
||||
assert activity_data["id"] == data["id"]
|
||||
assert activity_data["object"] == activity.data["object"]
|
||||
assert activity_data["content"] == "🍮"
|
||||
end
|
||||
|
||||
test "it works for incoming misskey likes that contain unicode emojis, turning them into EmojiReacts" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/misskey-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|> Map.put("_misskey_reaction", "⭐")
|
||||
|
||||
_actor = insert(:user, ap_id: data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: activity_data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert activity_data["actor"] == data["actor"]
|
||||
assert activity_data["type"] == "EmojiReact"
|
||||
assert activity_data["id"] == data["id"]
|
||||
assert activity_data["object"] == activity.data["object"]
|
||||
assert activity_data["content"] == "⭐"
|
||||
end
|
||||
end
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
# 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.UndoHandlingTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "it works for incoming emoji reaction undos" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||
{:ok, reaction_activity} = CommonAPI.react_with_emoji(activity.id, user, "👌")
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-undo-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", reaction_activity.data["id"])
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|
||||
{:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert activity.actor == user.ap_id
|
||||
assert activity.data["id"] == data["id"]
|
||||
assert activity.data["type"] == "Undo"
|
||||
end
|
||||
|
||||
test "it returns an error for incoming unlikes wihout a like activity" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"})
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-undo-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
assert Transmogrifier.handle_incoming(data) == :error
|
||||
end
|
||||
|
||||
test "it works for incoming unlikes with an existing like activity" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"})
|
||||
|
||||
like_data =
|
||||
File.read!("test/fixtures/mastodon-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_liker = insert(:user, ap_id: like_data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-undo-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", like_data)
|
||||
|> Map.put("actor", like_data["actor"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Undo"
|
||||
assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
|
||||
assert data["object"] == "http://mastodon.example.org/users/admin#likes/2"
|
||||
|
||||
note = Object.get_by_ap_id(like_data["object"])
|
||||
assert note.data["like_count"] == 0
|
||||
assert note.data["likes"] == []
|
||||
end
|
||||
|
||||
test "it works for incoming unlikes with an existing like activity and a compact object" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"})
|
||||
|
||||
like_data =
|
||||
File.read!("test/fixtures/mastodon-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_liker = insert(:user, ap_id: like_data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-undo-like.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", like_data["id"])
|
||||
|> Map.put("actor", like_data["actor"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
assert data["type"] == "Undo"
|
||||
assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
|
||||
assert data["object"] == "http://mastodon.example.org/users/admin#likes/2"
|
||||
end
|
||||
|
||||
test "it works for incoming unannounces with an existing notice" do
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
|
||||
announce_data =
|
||||
File.read!("test/fixtures/mastodon-announce.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", activity.data["object"])
|
||||
|
||||
_announcer = insert(:user, ap_id: announce_data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: announce_data, local: false}} =
|
||||
Transmogrifier.handle_incoming(announce_data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-undo-announce.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", announce_data)
|
||||
|> Map.put("actor", announce_data["actor"])
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["type"] == "Undo"
|
||||
|
||||
assert data["object"] ==
|
||||
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
|
||||
end
|
||||
|
||||
test "it works for incoming unfollows with an existing follow" do
|
||||
user = insert(:user)
|
||||
|
||||
follow_data =
|
||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
_follower = insert(:user, ap_id: follow_data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-unfollow-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", follow_data)
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert data["type"] == "Undo"
|
||||
assert data["object"]["type"] == "Follow"
|
||||
assert data["object"]["object"] == user.ap_id
|
||||
assert data["actor"] == "http://mastodon.example.org/users/admin"
|
||||
|
||||
refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
|
||||
end
|
||||
|
||||
test "it works for incoming unblocks with an existing block" do
|
||||
user = insert(:user)
|
||||
|
||||
block_data =
|
||||
File.read!("test/fixtures/mastodon-block-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", user.ap_id)
|
||||
|
||||
_blocker = insert(:user, ap_id: block_data["actor"], local: false)
|
||||
|
||||
{:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
|
||||
|
||||
data =
|
||||
File.read!("test/fixtures/mastodon-unblock-activity.json")
|
||||
|> Poison.decode!()
|
||||
|> Map.put("object", block_data)
|
||||
|
||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||
assert data["type"] == "Undo"
|
||||
assert data["object"] == block_data["id"]
|
||||
|
||||
blocker = User.get_cached_by_ap_id(data["actor"])
|
||||
|
||||
refute User.blocks?(blocker, user)
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,548 +0,0 @@
|
|||
# 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.UtilsTest do
|
||||
use Pleroma.DataCase
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.AdminAPI.AccountView
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
describe "fetch the latest Follow" do
|
||||
test "fetches the latest Follow activity" do
|
||||
%Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
|
||||
follower = User.get_cached_by_ap_id(activity.data["actor"])
|
||||
followed = User.get_cached_by_ap_id(activity.data["object"])
|
||||
|
||||
assert activity == Utils.fetch_latest_follow(follower, followed)
|
||||
end
|
||||
end
|
||||
|
||||
describe "determine_explicit_mentions()" do
|
||||
test "works with an object that has mentions" do
|
||||
object = %{
|
||||
"tag" => [
|
||||
%{
|
||||
"type" => "Mention",
|
||||
"href" => "https://example.com/~alyssa",
|
||||
"name" => "Alyssa P. Hacker"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
|
||||
end
|
||||
|
||||
test "works with an object that does not have mentions" do
|
||||
object = %{
|
||||
"tag" => [
|
||||
%{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
|
||||
]
|
||||
}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == []
|
||||
end
|
||||
|
||||
test "works with an object that has mentions and other tags" do
|
||||
object = %{
|
||||
"tag" => [
|
||||
%{
|
||||
"type" => "Mention",
|
||||
"href" => "https://example.com/~alyssa",
|
||||
"name" => "Alyssa P. Hacker"
|
||||
},
|
||||
%{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
|
||||
]
|
||||
}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
|
||||
end
|
||||
|
||||
test "works with an object that has no tags" do
|
||||
object = %{}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == []
|
||||
end
|
||||
|
||||
test "works with an object that has only IR tags" do
|
||||
object = %{"tag" => ["2hu"]}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == []
|
||||
end
|
||||
|
||||
test "works with an object has tags as map" do
|
||||
object = %{
|
||||
"tag" => %{
|
||||
"type" => "Mention",
|
||||
"href" => "https://example.com/~alyssa",
|
||||
"name" => "Alyssa P. Hacker"
|
||||
}
|
||||
}
|
||||
|
||||
assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "make_like_data" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
[user: user, other_user: other_user, third_user: third_user]
|
||||
end
|
||||
|
||||
test "addresses actor's follower address if the activity is public", %{
|
||||
user: user,
|
||||
other_user: other_user,
|
||||
third_user: third_user
|
||||
} do
|
||||
expected_to = Enum.sort([user.ap_id, other_user.follower_address])
|
||||
expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(user, %{
|
||||
status:
|
||||
"hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
|
||||
})
|
||||
|
||||
%{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
|
||||
assert Enum.sort(to) == expected_to
|
||||
assert Enum.sort(cc) == expected_cc
|
||||
end
|
||||
|
||||
test "does not adress actor's follower address if the activity is not public", %{
|
||||
user: user,
|
||||
other_user: other_user,
|
||||
third_user: third_user
|
||||
} do
|
||||
expected_to = Enum.sort([user.ap_id])
|
||||
expected_cc = [third_user.ap_id]
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
|
||||
visibility: "private"
|
||||
})
|
||||
|
||||
%{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
|
||||
assert Enum.sort(to) == expected_to
|
||||
assert Enum.sort(cc) == expected_cc
|
||||
end
|
||||
end
|
||||
|
||||
test "make_json_ld_header/0" do
|
||||
assert Utils.make_json_ld_header() == %{
|
||||
"@context" => [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"http://localhost:4001/schemas/litepub-0.1.jsonld",
|
||||
%{
|
||||
"@language" => "und"
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
describe "get_existing_votes" do
|
||||
test "fetches existing votes" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "How do I pronounce LaTeX?",
|
||||
poll: %{
|
||||
options: ["laytekh", "lahtekh", "latex"],
|
||||
expires_in: 20,
|
||||
multiple: true
|
||||
}
|
||||
})
|
||||
|
||||
object = Object.normalize(activity)
|
||||
{:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
|
||||
assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
|
||||
end
|
||||
|
||||
test "fetches only Create activities" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "Are we living in a society?",
|
||||
poll: %{
|
||||
options: ["yes", "no"],
|
||||
expires_in: 20
|
||||
}
|
||||
})
|
||||
|
||||
object = Object.normalize(activity)
|
||||
{:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
|
||||
{:ok, _activity} = CommonAPI.favorite(user, activity.id)
|
||||
[fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
|
||||
assert fetched_vote.id == vote.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_follow_state_for_all/2" do
|
||||
test "updates the state of all Follow activities with the same actor and object" do
|
||||
user = insert(:user, locked: true)
|
||||
follower = insert(:user)
|
||||
|
||||
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
|
||||
{:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
|
||||
|
||||
data =
|
||||
follow_activity_two.data
|
||||
|> Map.put("state", "accept")
|
||||
|
||||
cng = Ecto.Changeset.change(follow_activity_two, data: data)
|
||||
|
||||
{:ok, follow_activity_two} = Repo.update(cng)
|
||||
|
||||
{:ok, follow_activity_two} =
|
||||
Utils.update_follow_state_for_all(follow_activity_two, "accept")
|
||||
|
||||
assert refresh_record(follow_activity).data["state"] == "accept"
|
||||
assert refresh_record(follow_activity_two).data["state"] == "accept"
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_follow_state/2" do
|
||||
test "updates the state of the given follow activity" do
|
||||
user = insert(:user, locked: true)
|
||||
follower = insert(:user)
|
||||
|
||||
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
|
||||
{:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
|
||||
|
||||
data =
|
||||
follow_activity_two.data
|
||||
|> Map.put("state", "accept")
|
||||
|
||||
cng = Ecto.Changeset.change(follow_activity_two, data: data)
|
||||
|
||||
{:ok, follow_activity_two} = Repo.update(cng)
|
||||
|
||||
{:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
|
||||
|
||||
assert refresh_record(follow_activity).data["state"] == "pending"
|
||||
assert refresh_record(follow_activity_two).data["state"] == "reject"
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_element_in_object/3" do
|
||||
test "updates likes" do
|
||||
user = insert(:user)
|
||||
activity = insert(:note_activity)
|
||||
object = Object.normalize(activity)
|
||||
|
||||
assert {:ok, updated_object} =
|
||||
Utils.update_element_in_object(
|
||||
"like",
|
||||
[user.ap_id],
|
||||
object
|
||||
)
|
||||
|
||||
assert updated_object.data["likes"] == [user.ap_id]
|
||||
assert updated_object.data["like_count"] == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "add_like_to_object/2" do
|
||||
test "add actor to likes" do
|
||||
user = insert(:user)
|
||||
user2 = insert(:user)
|
||||
object = insert(:note)
|
||||
|
||||
assert {:ok, updated_object} =
|
||||
Utils.add_like_to_object(
|
||||
%Activity{data: %{"actor" => user.ap_id}},
|
||||
object
|
||||
)
|
||||
|
||||
assert updated_object.data["likes"] == [user.ap_id]
|
||||
assert updated_object.data["like_count"] == 1
|
||||
|
||||
assert {:ok, updated_object2} =
|
||||
Utils.add_like_to_object(
|
||||
%Activity{data: %{"actor" => user2.ap_id}},
|
||||
updated_object
|
||||
)
|
||||
|
||||
assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
|
||||
assert updated_object2.data["like_count"] == 2
|
||||
end
|
||||
end
|
||||
|
||||
describe "remove_like_from_object/2" do
|
||||
test "removes ap_id from likes" do
|
||||
user = insert(:user)
|
||||
user2 = insert(:user)
|
||||
object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
|
||||
|
||||
assert {:ok, updated_object} =
|
||||
Utils.remove_like_from_object(
|
||||
%Activity{data: %{"actor" => user.ap_id}},
|
||||
object
|
||||
)
|
||||
|
||||
assert updated_object.data["likes"] == [user2.ap_id]
|
||||
assert updated_object.data["like_count"] == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_existing_like/2" do
|
||||
test "fetches existing like" do
|
||||
note_activity = insert(:note_activity)
|
||||
assert object = Object.normalize(note_activity)
|
||||
|
||||
user = insert(:user)
|
||||
refute Utils.get_existing_like(user.ap_id, object)
|
||||
{:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
|
||||
|
||||
assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_get_existing_announce/2" do
|
||||
test "returns nil if announce not found" do
|
||||
actor = insert(:user)
|
||||
refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
|
||||
end
|
||||
|
||||
test "fetches existing announce" do
|
||||
note_activity = insert(:note_activity)
|
||||
assert object = Object.normalize(note_activity)
|
||||
actor = insert(:user)
|
||||
|
||||
{:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
|
||||
assert Utils.get_existing_announce(actor.ap_id, object) == announce
|
||||
end
|
||||
end
|
||||
|
||||
describe "fetch_latest_block/2" do
|
||||
test "fetches last block activities" do
|
||||
user1 = insert(:user)
|
||||
user2 = insert(:user)
|
||||
|
||||
assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
|
||||
assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
|
||||
assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)
|
||||
|
||||
assert Utils.fetch_latest_block(user1, user2) == activity
|
||||
end
|
||||
end
|
||||
|
||||
describe "recipient_in_message/3" do
|
||||
test "returns true when recipient in `to`" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
|
||||
|
||||
assert Utils.recipient_in_message(
|
||||
recipient,
|
||||
actor,
|
||||
%{"to" => [recipient.ap_id], "cc" => ""}
|
||||
)
|
||||
end
|
||||
|
||||
test "returns true when recipient in `cc`" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
|
||||
|
||||
assert Utils.recipient_in_message(
|
||||
recipient,
|
||||
actor,
|
||||
%{"cc" => [recipient.ap_id], "to" => ""}
|
||||
)
|
||||
end
|
||||
|
||||
test "returns true when recipient in `bto`" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
|
||||
|
||||
assert Utils.recipient_in_message(
|
||||
recipient,
|
||||
actor,
|
||||
%{"bcc" => "", "bto" => [recipient.ap_id]}
|
||||
)
|
||||
end
|
||||
|
||||
test "returns true when recipient in `bcc`" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
|
||||
|
||||
assert Utils.recipient_in_message(
|
||||
recipient,
|
||||
actor,
|
||||
%{"bto" => "", "bcc" => [recipient.ap_id]}
|
||||
)
|
||||
end
|
||||
|
||||
test "returns true when message without addresses fields" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
|
||||
|
||||
assert Utils.recipient_in_message(
|
||||
recipient,
|
||||
actor,
|
||||
%{"btod" => "", "bccc" => [recipient.ap_id]}
|
||||
)
|
||||
end
|
||||
|
||||
test "returns false" do
|
||||
recipient = insert(:user)
|
||||
actor = insert(:user)
|
||||
refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
|
||||
end
|
||||
end
|
||||
|
||||
describe "lazy_put_activity_defaults/2" do
|
||||
test "returns map with id and published data" do
|
||||
note_activity = insert(:note_activity)
|
||||
object = Object.normalize(note_activity)
|
||||
res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
|
||||
assert res["context"] == object.data["id"]
|
||||
assert res["context_id"] == object.id
|
||||
assert res["id"]
|
||||
assert res["published"]
|
||||
end
|
||||
|
||||
test "returns map with fake id and published data" do
|
||||
assert %{
|
||||
"context" => "pleroma:fakecontext",
|
||||
"context_id" => -1,
|
||||
"id" => "pleroma:fakeid",
|
||||
"published" => _
|
||||
} = Utils.lazy_put_activity_defaults(%{}, true)
|
||||
end
|
||||
|
||||
test "returns activity data with object" do
|
||||
note_activity = insert(:note_activity)
|
||||
object = Object.normalize(note_activity)
|
||||
|
||||
res =
|
||||
Utils.lazy_put_activity_defaults(%{
|
||||
"context" => object.data["id"],
|
||||
"object" => %{}
|
||||
})
|
||||
|
||||
assert res["context"] == object.data["id"]
|
||||
assert res["context_id"] == object.id
|
||||
assert res["id"]
|
||||
assert res["published"]
|
||||
assert res["object"]["id"]
|
||||
assert res["object"]["published"]
|
||||
assert res["object"]["context"] == object.data["id"]
|
||||
assert res["object"]["context_id"] == object.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "make_flag_data" do
|
||||
test "returns empty map when params is invalid" do
|
||||
assert Utils.make_flag_data(%{}, %{}) == %{}
|
||||
end
|
||||
|
||||
test "returns map with Flag object" do
|
||||
reporter = insert(:user)
|
||||
target_account = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
|
||||
context = Utils.generate_context_id()
|
||||
content = "foobar"
|
||||
|
||||
target_ap_id = target_account.ap_id
|
||||
activity_ap_id = activity.data["id"]
|
||||
|
||||
res =
|
||||
Utils.make_flag_data(
|
||||
%{
|
||||
actor: reporter,
|
||||
context: context,
|
||||
account: target_account,
|
||||
statuses: [%{"id" => activity.data["id"]}],
|
||||
content: content
|
||||
},
|
||||
%{}
|
||||
)
|
||||
|
||||
note_obj = %{
|
||||
"type" => "Note",
|
||||
"id" => activity_ap_id,
|
||||
"content" => content,
|
||||
"published" => activity.object.data["published"],
|
||||
"actor" =>
|
||||
AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
|
||||
}
|
||||
|
||||
assert %{
|
||||
"type" => "Flag",
|
||||
"content" => ^content,
|
||||
"context" => ^context,
|
||||
"object" => [^target_ap_id, ^note_obj],
|
||||
"state" => "open"
|
||||
} = res
|
||||
end
|
||||
end
|
||||
|
||||
describe "add_announce_to_object/2" do
|
||||
test "adds actor to announcement" do
|
||||
user = insert(:user)
|
||||
object = insert(:note)
|
||||
|
||||
activity =
|
||||
insert(:note_activity,
|
||||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"cc" => [Pleroma.Constants.as_public()]
|
||||
}
|
||||
)
|
||||
|
||||
assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
|
||||
assert updated_object.data["announcements"] == [user.ap_id]
|
||||
assert updated_object.data["announcement_count"] == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "remove_announce_from_object/2" do
|
||||
test "removes actor from announcements" do
|
||||
user = insert(:user)
|
||||
user2 = insert(:user)
|
||||
|
||||
object =
|
||||
insert(:note,
|
||||
data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
|
||||
)
|
||||
|
||||
activity = insert(:note_activity, data: %{"actor" => user.ap_id})
|
||||
|
||||
assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
|
||||
assert updated_object.data["announcements"] == [user2.ap_id]
|
||||
assert updated_object.data["announcement_count"] == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_cached_emoji_reactions/1" do
|
||||
test "returns the data or an emtpy list" do
|
||||
object = insert(:note)
|
||||
assert Utils.get_cached_emoji_reactions(object) == []
|
||||
|
||||
object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
|
||||
assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
|
||||
|
||||
object = insert(:note, data: %{"reactions" => %{}})
|
||||
assert Utils.get_cached_emoji_reactions(object) == []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
# 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.ObjectViewTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.ObjectView
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
test "renders a note object" do
|
||||
note = insert(:note)
|
||||
|
||||
result = ObjectView.render("object.json", %{object: note})
|
||||
|
||||
assert result["id"] == note.data["id"]
|
||||
assert result["to"] == note.data["to"]
|
||||
assert result["content"] == note.data["content"]
|
||||
assert result["type"] == "Note"
|
||||
assert result["@context"]
|
||||
end
|
||||
|
||||
test "renders a note activity" do
|
||||
note = insert(:note_activity)
|
||||
object = Object.normalize(note)
|
||||
|
||||
result = ObjectView.render("object.json", %{object: note})
|
||||
|
||||
assert result["id"] == note.data["id"]
|
||||
assert result["to"] == note.data["to"]
|
||||
assert result["object"]["type"] == "Note"
|
||||
assert result["object"]["content"] == object.data["content"]
|
||||
assert result["type"] == "Create"
|
||||
assert result["@context"]
|
||||
end
|
||||
|
||||
describe "note activity's `replies` collection rendering" do
|
||||
setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
|
||||
|
||||
test "renders `replies` collection for a note activity" do
|
||||
user = insert(:user)
|
||||
activity = insert(:note_activity, user: user)
|
||||
|
||||
{:ok, self_reply1} =
|
||||
CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: activity.id})
|
||||
|
||||
replies_uris = [self_reply1.object.data["id"]]
|
||||
result = ObjectView.render("object.json", %{object: refresh_record(activity)})
|
||||
|
||||
assert %{"type" => "Collection", "items" => ^replies_uris} =
|
||||
get_in(result, ["object", "replies"])
|
||||
end
|
||||
end
|
||||
|
||||
test "renders a like activity" do
|
||||
note = insert(:note_activity)
|
||||
object = Object.normalize(note)
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, like_activity} = CommonAPI.favorite(user, note.id)
|
||||
|
||||
result = ObjectView.render("object.json", %{object: like_activity})
|
||||
|
||||
assert result["id"] == like_activity.data["id"]
|
||||
assert result["object"] == object.data["id"]
|
||||
assert result["type"] == "Like"
|
||||
end
|
||||
|
||||
test "renders an announce activity" do
|
||||
note = insert(:note_activity)
|
||||
object = Object.normalize(note)
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, announce_activity} = CommonAPI.repeat(note.id, user)
|
||||
|
||||
result = ObjectView.render("object.json", %{object: announce_activity})
|
||||
|
||||
assert result["id"] == announce_activity.data["id"]
|
||||
assert result["object"] == object.data["id"]
|
||||
assert result["type"] == "Announce"
|
||||
end
|
||||
end
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
# 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.UserViewTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.UserView
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
test "Renders a user, including the public key" do
|
||||
user = insert(:user)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
|
||||
assert result["id"] == user.ap_id
|
||||
assert result["preferredUsername"] == user.nickname
|
||||
|
||||
assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY")
|
||||
end
|
||||
|
||||
test "Renders profile fields" do
|
||||
fields = [
|
||||
%{"name" => "foo", "value" => "bar"}
|
||||
]
|
||||
|
||||
{:ok, user} =
|
||||
insert(:user)
|
||||
|> User.update_changeset(%{fields: fields})
|
||||
|> User.update_and_set_cache()
|
||||
|
||||
assert %{
|
||||
"attachment" => [%{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}]
|
||||
} = UserView.render("user.json", %{user: user})
|
||||
end
|
||||
|
||||
test "Renders with emoji tags" do
|
||||
user = insert(:user, emoji: %{"bib" => "/test"})
|
||||
|
||||
assert %{
|
||||
"tag" => [
|
||||
%{
|
||||
"icon" => %{"type" => "Image", "url" => "/test"},
|
||||
"id" => "/test",
|
||||
"name" => ":bib:",
|
||||
"type" => "Emoji",
|
||||
"updated" => "1970-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
} = UserView.render("user.json", %{user: user})
|
||||
end
|
||||
|
||||
test "Does not add an avatar image if the user hasn't set one" do
|
||||
user = insert(:user)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
refute result["icon"]
|
||||
refute result["image"]
|
||||
|
||||
user =
|
||||
insert(:user,
|
||||
avatar: %{"url" => [%{"href" => "https://someurl"}]},
|
||||
banner: %{"url" => [%{"href" => "https://somebanner"}]}
|
||||
)
|
||||
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
assert result["icon"]["url"] == "https://someurl"
|
||||
assert result["image"]["url"] == "https://somebanner"
|
||||
end
|
||||
|
||||
test "renders an invisible user with the invisible property set to true" do
|
||||
user = insert(:user, invisible: true)
|
||||
|
||||
assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
|
||||
end
|
||||
|
||||
describe "endpoints" do
|
||||
test "local users have a usable endpoints structure" do
|
||||
user = insert(:user)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
|
||||
assert result["id"] == user.ap_id
|
||||
|
||||
%{
|
||||
"sharedInbox" => _,
|
||||
"oauthAuthorizationEndpoint" => _,
|
||||
"oauthRegistrationEndpoint" => _,
|
||||
"oauthTokenEndpoint" => _
|
||||
} = result["endpoints"]
|
||||
end
|
||||
|
||||
test "remote users have an empty endpoints structure" do
|
||||
user = insert(:user, local: false)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
|
||||
assert result["id"] == user.ap_id
|
||||
assert result["endpoints"] == %{}
|
||||
end
|
||||
|
||||
test "instance users do not expose oAuth endpoints" do
|
||||
user = insert(:user, nickname: nil, local: true)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
|
||||
result = UserView.render("user.json", %{user: user})
|
||||
|
||||
refute result["endpoints"]["oauthAuthorizationEndpoint"]
|
||||
refute result["endpoints"]["oauthRegistrationEndpoint"]
|
||||
refute result["endpoints"]["oauthTokenEndpoint"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "followers" do
|
||||
test "sets totalItems to zero when followers are hidden" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
|
||||
assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
|
||||
user = Map.merge(user, %{hide_followers_count: true, hide_followers: true})
|
||||
refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems")
|
||||
end
|
||||
|
||||
test "sets correct totalItems when followers are hidden but the follower counter is not" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
|
||||
assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
|
||||
user = Map.merge(user, %{hide_followers_count: false, hide_followers: true})
|
||||
assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
|
||||
end
|
||||
end
|
||||
|
||||
describe "following" do
|
||||
test "sets totalItems to zero when follows are hidden" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
|
||||
assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})
|
||||
user = Map.merge(user, %{hide_follows_count: true, hide_follows: true})
|
||||
assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user})
|
||||
end
|
||||
|
||||
test "sets correct totalItems when follows are hidden but the follow counter is not" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
|
||||
assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})
|
||||
user = Map.merge(user, %{hide_follows_count: false, hide_follows: true})
|
||||
assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})
|
||||
end
|
||||
end
|
||||
|
||||
describe "acceptsChatMessages" do
|
||||
test "it returns this value if it is set" do
|
||||
true_user = insert(:user, accepts_chat_messages: true)
|
||||
false_user = insert(:user, accepts_chat_messages: false)
|
||||
nil_user = insert(:user, accepts_chat_messages: nil)
|
||||
|
||||
assert %{"capabilities" => %{"acceptsChatMessages" => true}} =
|
||||
UserView.render("user.json", user: true_user)
|
||||
|
||||
assert %{"capabilities" => %{"acceptsChatMessages" => false}} =
|
||||
UserView.render("user.json", user: false_user)
|
||||
|
||||
refute Map.has_key?(
|
||||
UserView.render("user.json", user: nil_user)["capabilities"],
|
||||
"acceptsChatMessages"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
# 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.VisibilityTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.CommonAPI
|
||||
import Pleroma.Factory
|
||||
|
||||
setup do
|
||||
user = insert(:user)
|
||||
mentioned = insert(:user)
|
||||
following = insert(:user)
|
||||
unrelated = insert(:user)
|
||||
{:ok, following} = Pleroma.User.follow(following, user)
|
||||
{:ok, list} = Pleroma.List.create("foo", user)
|
||||
|
||||
Pleroma.List.follow(list, unrelated)
|
||||
|
||||
{:ok, public} =
|
||||
CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "public"})
|
||||
|
||||
{:ok, private} =
|
||||
CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "private"})
|
||||
|
||||
{:ok, direct} =
|
||||
CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "direct"})
|
||||
|
||||
{:ok, unlisted} =
|
||||
CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "unlisted"})
|
||||
|
||||
{:ok, list} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "@#{mentioned.nickname}",
|
||||
visibility: "list:#{list.id}"
|
||||
})
|
||||
|
||||
%{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
user: user,
|
||||
mentioned: mentioned,
|
||||
following: following,
|
||||
unrelated: unrelated,
|
||||
list: list
|
||||
}
|
||||
end
|
||||
|
||||
test "is_direct?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
assert Visibility.is_direct?(direct)
|
||||
refute Visibility.is_direct?(public)
|
||||
refute Visibility.is_direct?(private)
|
||||
refute Visibility.is_direct?(unlisted)
|
||||
assert Visibility.is_direct?(list)
|
||||
end
|
||||
|
||||
test "is_public?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_public?(direct)
|
||||
assert Visibility.is_public?(public)
|
||||
refute Visibility.is_public?(private)
|
||||
assert Visibility.is_public?(unlisted)
|
||||
refute Visibility.is_public?(list)
|
||||
end
|
||||
|
||||
test "is_private?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_private?(direct)
|
||||
refute Visibility.is_private?(public)
|
||||
assert Visibility.is_private?(private)
|
||||
refute Visibility.is_private?(unlisted)
|
||||
refute Visibility.is_private?(list)
|
||||
end
|
||||
|
||||
test "is_list?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_list?(direct)
|
||||
refute Visibility.is_list?(public)
|
||||
refute Visibility.is_list?(private)
|
||||
refute Visibility.is_list?(unlisted)
|
||||
assert Visibility.is_list?(list)
|
||||
end
|
||||
|
||||
test "visible_for_user?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
user: user,
|
||||
mentioned: mentioned,
|
||||
following: following,
|
||||
unrelated: unrelated,
|
||||
list: list
|
||||
} do
|
||||
# All visible to author
|
||||
|
||||
assert Visibility.visible_for_user?(public, user)
|
||||
assert Visibility.visible_for_user?(private, user)
|
||||
assert Visibility.visible_for_user?(unlisted, user)
|
||||
assert Visibility.visible_for_user?(direct, user)
|
||||
assert Visibility.visible_for_user?(list, user)
|
||||
|
||||
# All visible to a mentioned user
|
||||
|
||||
assert Visibility.visible_for_user?(public, mentioned)
|
||||
assert Visibility.visible_for_user?(private, mentioned)
|
||||
assert Visibility.visible_for_user?(unlisted, mentioned)
|
||||
assert Visibility.visible_for_user?(direct, mentioned)
|
||||
assert Visibility.visible_for_user?(list, mentioned)
|
||||
|
||||
# DM not visible for just follower
|
||||
|
||||
assert Visibility.visible_for_user?(public, following)
|
||||
assert Visibility.visible_for_user?(private, following)
|
||||
assert Visibility.visible_for_user?(unlisted, following)
|
||||
refute Visibility.visible_for_user?(direct, following)
|
||||
refute Visibility.visible_for_user?(list, following)
|
||||
|
||||
# Public and unlisted visible for unrelated user
|
||||
|
||||
assert Visibility.visible_for_user?(public, unrelated)
|
||||
assert Visibility.visible_for_user?(unlisted, unrelated)
|
||||
refute Visibility.visible_for_user?(private, unrelated)
|
||||
refute Visibility.visible_for_user?(direct, unrelated)
|
||||
|
||||
# Visible for a list member
|
||||
assert Visibility.visible_for_user?(list, unrelated)
|
||||
end
|
||||
|
||||
test "doesn't die when the user doesn't exist",
|
||||
%{
|
||||
direct: direct,
|
||||
user: user
|
||||
} do
|
||||
Repo.delete(user)
|
||||
Cachex.clear(:user_cache)
|
||||
refute Visibility.is_private?(direct)
|
||||
end
|
||||
|
||||
test "get_visibility", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
assert Visibility.get_visibility(public) == "public"
|
||||
assert Visibility.get_visibility(private) == "private"
|
||||
assert Visibility.get_visibility(direct) == "direct"
|
||||
assert Visibility.get_visibility(unlisted) == "unlisted"
|
||||
assert Visibility.get_visibility(list) == "list"
|
||||
end
|
||||
|
||||
test "get_visibility with directMessage flag" do
|
||||
assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct"
|
||||
end
|
||||
|
||||
test "get_visibility with listMessage flag" do
|
||||
assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "list"
|
||||
end
|
||||
|
||||
describe "entire_thread_visible_for_user?/2" do
|
||||
test "returns false if not found activity", %{user: user} do
|
||||
refute Visibility.entire_thread_visible_for_user?(%Activity{}, user)
|
||||
end
|
||||
|
||||
test "returns true if activity hasn't 'Create' type", %{user: user} do
|
||||
activity = insert(:like_activity)
|
||||
assert Visibility.entire_thread_visible_for_user?(activity, user)
|
||||
end
|
||||
|
||||
test "returns false when invalid recipients", %{user: user} do
|
||||
author = insert(:user)
|
||||
|
||||
activity =
|
||||
insert(:note_activity,
|
||||
note:
|
||||
insert(:note,
|
||||
user: author,
|
||||
data: %{"to" => ["test-user"]}
|
||||
)
|
||||
)
|
||||
|
||||
refute Visibility.entire_thread_visible_for_user?(activity, user)
|
||||
end
|
||||
|
||||
test "returns true if user following to author" do
|
||||
author = insert(:user)
|
||||
user = insert(:user)
|
||||
Pleroma.User.follow(user, author)
|
||||
|
||||
activity =
|
||||
insert(:note_activity,
|
||||
note:
|
||||
insert(:note,
|
||||
user: author,
|
||||
data: %{"to" => [user.ap_id]}
|
||||
)
|
||||
)
|
||||
|
||||
assert Visibility.entire_thread_visible_for_user?(activity, user)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue