Fix MRF policies to also work with Update
Objects who got updated would just pass through several of the MRF policies, undoing moderation in some situations. In the relevant cases we now check not only for Create activities, but also Update activities. I checked which ones checked explicitly on type Create using `grep '"type" => "Create"' lib/pleroma/web/activity_pub/mrf/*`. The following from that list have not been changed: * lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex * Not relevant for moderation * lib/pleroma/web/activity_pub/mrf/keyword_policy.ex * Already had a test for Update * lib/pleroma/web/activity_pub/mrf/object_age_policy.ex * In practice only relevant when fetching old objects (e.g. through Like or Announce). These are always wrapped in a Create. * lib/pleroma/web/activity_pub/mrf/reject_non_public.ex * We don't allow changing scope with Update, so not relevant here
This commit is contained in:
parent
ce517ff4e5
commit
1f863f0a36
13 changed files with 308 additions and 22 deletions
|
@ -3,7 +3,7 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
|
||||||
@moduledoc "Adds expiration to all local Create activities"
|
@moduledoc "Adds expiration to all local Create/Update activities"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -25,8 +25,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
|
||||||
String.starts_with?(actor, Pleroma.Web.Endpoint.url())
|
String.starts_with?(actor, Pleroma.Web.Endpoint.url())
|
||||||
end
|
end
|
||||||
|
|
||||||
defp note?(activity) do
|
defp note?(%{"type" => type, "object" => %{"type" => "Note"}})
|
||||||
match?(%{"type" => "Create", "object" => %{"type" => "Note"}}, activity)
|
when type in ["Create", "Update"] do
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
defp note?(_) do
|
||||||
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_add_expiration(activity) do
|
defp maybe_add_expiration(activity) do
|
||||||
|
|
|
@ -29,7 +29,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
||||||
defp contains_links?(_), do: false
|
defp contains_links?(_), do: false
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
def filter(%{"type" => type, "actor" => actor, "object" => object} = message)
|
||||||
|
when type in ["Create", "Update"] do
|
||||||
with {:ok, %User{local: false} = u} <- User.get_or_fetch_by_ap_id(actor),
|
with {:ok, %User{local: false} = u} <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
||||||
{:old_user, true} <- {:old_user, old_user?(u)} do
|
{:old_user, true} <- {:old_user, old_user?(u)} do
|
||||||
|
|
|
@ -17,13 +17,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
|
||||||
@impl true
|
@impl true
|
||||||
def filter(
|
def filter(
|
||||||
%{
|
%{
|
||||||
"type" => "Create",
|
"type" => type,
|
||||||
"to" => to,
|
"to" => to,
|
||||||
"cc" => cc,
|
"cc" => cc,
|
||||||
"actor" => actor,
|
"actor" => actor,
|
||||||
"object" => object
|
"object" => object
|
||||||
} = message
|
} = message
|
||||||
) do
|
)
|
||||||
|
when type in ["Create", "Update"] do
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
isbot = check_if_bot(user)
|
isbot = check_if_bot(user)
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Create", "object" => %{"type" => object_type}} = message)
|
def filter(%{"type" => type, "object" => %{"type" => object_type}} = message)
|
||||||
when object_type in ~w{Note Article} do
|
when type in ~w{Create Update} and object_type in ~w{Note Article} do
|
||||||
reject_threshold =
|
reject_threshold =
|
||||||
Pleroma.Config.get(
|
Pleroma.Config.get(
|
||||||
[:mrf_hellthread, :reject_threshold],
|
[:mrf_hellthread, :reject_threshold],
|
||||||
|
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Create"} = message) do
|
def filter(%{"type" => type} = message) when type in ["Create", "Update"] do
|
||||||
reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
|
reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
|
||||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||||
|
|
||||||
defp check_media_removal(
|
defp check_media_removal(
|
||||||
%{host: actor_host} = _actor_info,
|
%{host: actor_host} = _actor_info,
|
||||||
%{"type" => "Create", "object" => %{"attachment" => child_attachment}} = object
|
%{"type" => type, "object" => %{"attachment" => child_attachment}} = object
|
||||||
)
|
)
|
||||||
when length(child_attachment) > 0 do
|
when type in ["Create", "Update"] and length(child_attachment) > 0 do
|
||||||
media_removal =
|
media_removal =
|
||||||
instance_list(:media_removal)
|
instance_list(:media_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
@ -63,10 +63,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||||
defp check_media_nsfw(
|
defp check_media_nsfw(
|
||||||
%{host: actor_host} = _actor_info,
|
%{host: actor_host} = _actor_info,
|
||||||
%{
|
%{
|
||||||
"type" => "Create",
|
"type" => type,
|
||||||
"object" => %{} = _child_object
|
"object" => %{} = _child_object
|
||||||
} = object
|
} = object
|
||||||
) do
|
)
|
||||||
|
when type in ["Create", "Update"] do
|
||||||
media_nsfw =
|
media_nsfw =
|
||||||
instance_list(:media_nsfw)
|
instance_list(:media_nsfw)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
|
@ -58,7 +58,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
||||||
"actor" => actor,
|
"actor" => actor,
|
||||||
"object" => object
|
"object" => object
|
||||||
} = message
|
} = message
|
||||||
) when type in ["Create", "Update"] do
|
)
|
||||||
|
when type in ["Create", "Update"] do
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
|
|
||||||
if Enum.member?(to, Pleroma.Constants.as_public()) do
|
if Enum.member?(to, Pleroma.Constants.as_public()) do
|
||||||
|
@ -91,7 +92,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
||||||
"actor" => actor,
|
"actor" => actor,
|
||||||
"object" => object
|
"object" => object
|
||||||
} = message
|
} = message
|
||||||
) when type in ["Create", "Update"] do
|
)
|
||||||
|
when type in ["Create", "Update"] do
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
|
|
||||||
if Enum.member?(to, Pleroma.Constants.as_public()) or
|
if Enum.member?(to, Pleroma.Constants.as_public()) or
|
||||||
|
|
|
@ -19,6 +19,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
|
||||||
})
|
})
|
||||||
|
|
||||||
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||||
|
|
||||||
|
assert {:ok, %{"type" => "Update", "expires_at" => expires_at}} =
|
||||||
|
ActivityExpirationPolicy.filter(%{
|
||||||
|
"id" => @id,
|
||||||
|
"actor" => @local_actor,
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{"type" => "Note"}
|
||||||
|
})
|
||||||
|
|
||||||
|
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||||
end
|
end
|
||||||
|
|
||||||
test "keeps existing `expires_at` if it less than the config setting" do
|
test "keeps existing `expires_at` if it less than the config setting" do
|
||||||
|
@ -32,6 +42,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
|
||||||
"expires_at" => expires_at,
|
"expires_at" => expires_at,
|
||||||
"object" => %{"type" => "Note"}
|
"object" => %{"type" => "Note"}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert {:ok, %{"type" => "Update", "expires_at" => ^expires_at}} =
|
||||||
|
ActivityExpirationPolicy.filter(%{
|
||||||
|
"id" => @id,
|
||||||
|
"actor" => @local_actor,
|
||||||
|
"type" => "Update",
|
||||||
|
"expires_at" => expires_at,
|
||||||
|
"object" => %{"type" => "Note"}
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "overwrites existing `expires_at` if it greater than the config setting" do
|
test "overwrites existing `expires_at` if it greater than the config setting" do
|
||||||
|
@ -47,6 +66,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
|
||||||
})
|
})
|
||||||
|
|
||||||
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||||
|
|
||||||
|
assert {:ok, %{"type" => "Update", "expires_at" => expires_at}} =
|
||||||
|
ActivityExpirationPolicy.filter(%{
|
||||||
|
"id" => @id,
|
||||||
|
"actor" => @local_actor,
|
||||||
|
"type" => "Update",
|
||||||
|
"expires_at" => too_distant_future,
|
||||||
|
"object" => %{"type" => "Note"}
|
||||||
|
})
|
||||||
|
|
||||||
|
assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
|
||||||
end
|
end
|
||||||
|
|
||||||
test "ignores remote activities" do
|
test "ignores remote activities" do
|
||||||
|
@ -59,9 +89,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
|
||||||
})
|
})
|
||||||
|
|
||||||
refute Map.has_key?(activity, "expires_at")
|
refute Map.has_key?(activity, "expires_at")
|
||||||
|
|
||||||
|
assert {:ok, activity} =
|
||||||
|
ActivityExpirationPolicy.filter(%{
|
||||||
|
"id" => "https://example.com/123",
|
||||||
|
"actor" => "https://example.com/users/cofe",
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{"type" => "Note"}
|
||||||
|
})
|
||||||
|
|
||||||
|
refute Map.has_key?(activity, "expires_at")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "ignores non-Create/Note activities" do
|
test "ignores non-Create/Update/Note activities" do
|
||||||
assert {:ok, activity} =
|
assert {:ok, activity} =
|
||||||
ActivityExpirationPolicy.filter(%{
|
ActivityExpirationPolicy.filter(%{
|
||||||
"id" => "https://example.com/123",
|
"id" => "https://example.com/123",
|
||||||
|
|
|
@ -32,6 +32,28 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@linkless_update_message %{
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{
|
||||||
|
"content" => "hi world!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@linkful_update_message %{
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{
|
||||||
|
"content" => "<a href='https://example.com'>hi world!</a>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@response_update_message %{
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{
|
||||||
|
"name" => "yes",
|
||||||
|
"type" => "Answer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe "with new user" do
|
describe "with new user" do
|
||||||
test "it allows posts without links" do
|
test "it allows posts without links" do
|
||||||
user = insert(:user, local: false)
|
user = insert(:user, local: false)
|
||||||
|
@ -42,7 +64,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkless_message
|
@linkless_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkless_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it disallows posts with links" do
|
test "it disallows posts with links" do
|
||||||
|
@ -66,7 +93,24 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"actor" => user.ap_id,
|
||||||
|
"object" => %{
|
||||||
|
"formerRepresentations" => %{
|
||||||
|
"type" => "OrderedCollection",
|
||||||
|
"orderedItems" => [
|
||||||
|
%{
|
||||||
|
"content" => "<a href='https://example.com'>hi world!</a>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"content" => "mew"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{:reject, _} = MRF.filter_one(AntiLinkSpamPolicy, message)
|
{:reject, _} = MRF.filter_one(AntiLinkSpamPolicy, message)
|
||||||
|
{:reject, _} = MRF.filter_one(AntiLinkSpamPolicy, update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it allows posts with links for local users" do
|
test "it allows posts with links for local users" do
|
||||||
|
@ -78,7 +122,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkful_message
|
@linkful_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkful_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it disallows posts with links in history" do
|
test "it disallows posts with links in history" do
|
||||||
|
@ -90,7 +139,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkful_message
|
@linkful_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkful_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:reject, _} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,7 +158,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkless_message
|
@linkless_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkless_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it allows posts with links" do
|
test "it allows posts with links" do
|
||||||
|
@ -116,7 +175,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkful_message
|
@linkful_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkful_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -130,7 +194,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkless_message
|
@linkless_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkless_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it allows posts with links" do
|
test "it allows posts with links" do
|
||||||
|
@ -142,7 +211,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkful_message
|
@linkful_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkful_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -161,9 +235,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkless_message
|
@linkless_message
|
||||||
|> Map.put("actor", "http://invalid.actor")
|
|> Map.put("actor", "http://invalid.actor")
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkless_update_message
|
||||||
|
|> Map.put("actor", "http://invalid.actor")
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert capture_log(fn ->
|
||||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||||
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||||
|
|
||||||
|
assert capture_log(fn ->
|
||||||
|
{:reject, _} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
|
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it rejects posts with links" do
|
test "it rejects posts with links" do
|
||||||
|
@ -171,9 +253,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@linkful_message
|
@linkful_message
|
||||||
|> Map.put("actor", "http://invalid.actor")
|
|> Map.put("actor", "http://invalid.actor")
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@linkful_update_message
|
||||||
|
|> Map.put("actor", "http://invalid.actor")
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert capture_log(fn ->
|
||||||
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
{:reject, _} = AntiLinkSpamPolicy.filter(message)
|
||||||
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||||
|
|
||||||
|
assert capture_log(fn ->
|
||||||
|
{:reject, _} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
|
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -185,7 +275,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
|
||||||
@response_message
|
@response_message
|
||||||
|> Map.put("actor", user.ap_id)
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
|
update_message =
|
||||||
|
@response_update_message
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|
||||||
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
{:ok, _message} = AntiLinkSpamPolicy.filter(message)
|
||||||
|
{:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,35 +26,60 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicyTest do
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp generate_update_messages(actor) do
|
||||||
|
{%{
|
||||||
|
"actor" => actor.ap_id,
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{},
|
||||||
|
"to" => [@public, "f"],
|
||||||
|
"cc" => [actor.follower_address, "d"]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"actor" => actor.ap_id,
|
||||||
|
"type" => "Update",
|
||||||
|
"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
|
test "removes from the federated timeline by nickname heuristics 1" do
|
||||||
actor = insert(:user, %{nickname: "annoying_ebooks@example.com"})
|
actor = insert(:user, %{nickname: "annoying_ebooks@example.com"})
|
||||||
|
|
||||||
{message, except_message} = generate_messages(actor)
|
{message, except_message} = generate_messages(actor)
|
||||||
|
{update_message, except_update_message} = generate_update_messages(actor)
|
||||||
|
|
||||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||||
|
assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "removes from the federated timeline by nickname heuristics 2" do
|
test "removes from the federated timeline by nickname heuristics 2" do
|
||||||
actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"})
|
actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"})
|
||||||
|
|
||||||
{message, except_message} = generate_messages(actor)
|
{message, except_message} = generate_messages(actor)
|
||||||
|
{update_message, except_update_message} = generate_update_messages(actor)
|
||||||
|
|
||||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||||
|
assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "removes from the federated timeline by actor type Application" do
|
test "removes from the federated timeline by actor type Application" do
|
||||||
actor = insert(:user, %{actor_type: "Application"})
|
actor = insert(:user, %{actor_type: "Application"})
|
||||||
|
|
||||||
{message, except_message} = generate_messages(actor)
|
{message, except_message} = generate_messages(actor)
|
||||||
|
{update_message, except_update_message} = generate_update_messages(actor)
|
||||||
|
|
||||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||||
|
assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "removes from the federated timeline by actor type Service" do
|
test "removes from the federated timeline by actor type Service" do
|
||||||
actor = insert(:user, %{actor_type: "Service"})
|
actor = insert(:user, %{actor_type: "Service"})
|
||||||
|
|
||||||
{message, except_message} = generate_messages(actor)
|
{message, except_message} = generate_messages(actor)
|
||||||
|
{update_message, except_update_message} = generate_update_messages(actor)
|
||||||
|
|
||||||
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
|
||||||
|
assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,54 +26,86 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[user: user, message: message]
|
update_message = %{
|
||||||
|
"actor" => user.ap_id,
|
||||||
|
"cc" => [user.follower_address],
|
||||||
|
"type" => "Update",
|
||||||
|
"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, update_message: update_message]
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do: clear_config(:mrf_hellthread)
|
setup do: clear_config(:mrf_hellthread)
|
||||||
|
|
||||||
describe "reject" do
|
describe "reject" do
|
||||||
test "rejects the message if the recipient count is above reject_threshold", %{
|
test "rejects the message if the recipient count is above reject_threshold", %{
|
||||||
message: message
|
message: message,
|
||||||
|
update_message: update_message
|
||||||
} do
|
} do
|
||||||
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
|
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
|
||||||
|
|
||||||
assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
|
assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
|
||||||
filter(message)
|
filter(message)
|
||||||
|
|
||||||
|
assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
|
||||||
|
filter(update_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not reject the message if the recipient count is below reject_threshold", %{
|
test "does not reject the message if the recipient count is below reject_threshold", %{
|
||||||
message: message
|
message: message,
|
||||||
|
update_message: update_message
|
||||||
} do
|
} do
|
||||||
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
||||||
|
|
||||||
assert {:ok, ^message} = filter(message)
|
assert {:ok, ^message} = filter(message)
|
||||||
|
assert {:ok, ^update_message} = filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "delist" do
|
describe "delist" do
|
||||||
test "delists the message if the recipient count is above delist_threshold", %{
|
test "delists the message if the recipient count is above delist_threshold", %{
|
||||||
user: user,
|
user: user,
|
||||||
message: message
|
message: message,
|
||||||
|
update_message: update_message
|
||||||
} do
|
} do
|
||||||
clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
|
clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
|
||||||
|
|
||||||
{:ok, message} = filter(message)
|
{:ok, message} = filter(message)
|
||||||
assert user.follower_address in message["to"]
|
assert user.follower_address in message["to"]
|
||||||
assert "https://www.w3.org/ns/activitystreams#Public" in message["cc"]
|
assert "https://www.w3.org/ns/activitystreams#Public" in message["cc"]
|
||||||
|
|
||||||
|
{:ok, update_message} = filter(update_message)
|
||||||
|
assert user.follower_address in update_message["to"]
|
||||||
|
assert "https://www.w3.org/ns/activitystreams#Public" in update_message["cc"]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not delist the message if the recipient count is below delist_threshold", %{
|
test "does not delist the message if the recipient count is below delist_threshold", %{
|
||||||
message: message
|
message: message,
|
||||||
|
update_message: update_message
|
||||||
} do
|
} do
|
||||||
clear_config([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0})
|
clear_config([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0})
|
||||||
|
|
||||||
assert {:ok, ^message} = filter(message)
|
assert {:ok, ^message} = filter(message)
|
||||||
|
assert {:ok, ^update_message} = filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "excludes follower collection and public URI from threshold count", %{message: message} do
|
test "excludes follower collection and public URI from threshold count", %{
|
||||||
|
message: message,
|
||||||
|
update_message: update_message
|
||||||
|
} do
|
||||||
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
|
||||||
|
|
||||||
assert {:ok, ^message} = filter(message)
|
assert {:ok, ^message} = filter(message)
|
||||||
|
assert {:ok, ^update_message} = filter(update_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"cc" => ["https://example.com/blocked"]
|
"cc" => ["https://example.com/blocked"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"to" => ["https://example.com/ok"],
|
||||||
|
"cc" => ["https://example.com/blocked"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) == {:ok, message}
|
assert MentionPolicy.filter(message) == {:ok, message}
|
||||||
|
assert MentionPolicy.filter(update_message) == {:ok, update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "allow" do
|
describe "allow" do
|
||||||
|
@ -29,7 +36,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"type" => "Create"
|
"type" => "Create"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update"
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) == {:ok, message}
|
assert MentionPolicy.filter(message) == {:ok, message}
|
||||||
|
assert MentionPolicy.filter(update_message) == {:ok, update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "to" do
|
test "to" do
|
||||||
|
@ -40,7 +52,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"to" => ["https://example.com/ok"]
|
"to" => ["https://example.com/ok"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"to" => ["https://example.com/ok"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) == {:ok, message}
|
assert MentionPolicy.filter(message) == {:ok, message}
|
||||||
|
assert MentionPolicy.filter(update_message) == {:ok, update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "cc" do
|
test "cc" do
|
||||||
|
@ -51,7 +69,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"cc" => ["https://example.com/ok"]
|
"cc" => ["https://example.com/ok"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"cc" => ["https://example.com/ok"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) == {:ok, message}
|
assert MentionPolicy.filter(message) == {:ok, message}
|
||||||
|
assert MentionPolicy.filter(update_message) == {:ok, update_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "both" do
|
test "both" do
|
||||||
|
@ -63,7 +87,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"cc" => ["https://example.com/ok2"]
|
"cc" => ["https://example.com/ok2"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"to" => ["https://example.com/ok"],
|
||||||
|
"cc" => ["https://example.com/ok2"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) == {:ok, message}
|
assert MentionPolicy.filter(message) == {:ok, message}
|
||||||
|
assert MentionPolicy.filter(update_message) == {:ok, update_message}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -76,8 +107,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"to" => ["https://example.com/blocked"]
|
"to" => ["https://example.com/blocked"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"to" => ["https://example.com/blocked"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) ==
|
assert MentionPolicy.filter(message) ==
|
||||||
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||||
|
|
||||||
|
assert MentionPolicy.filter(update_message) ==
|
||||||
|
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "cc" do
|
test "cc" do
|
||||||
|
@ -89,8 +128,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
"cc" => ["https://example.com/blocked"]
|
"cc" => ["https://example.com/blocked"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_message = %{
|
||||||
|
"type" => "Update",
|
||||||
|
"to" => ["https://example.com/ok"],
|
||||||
|
"cc" => ["https://example.com/blocked"]
|
||||||
|
}
|
||||||
|
|
||||||
assert MentionPolicy.filter(message) ==
|
assert MentionPolicy.filter(message) ==
|
||||||
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||||
|
|
||||||
|
assert MentionPolicy.filter(update_message) ==
|
||||||
|
{:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,15 +26,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
test "is empty" do
|
test "is empty" do
|
||||||
clear_config([:mrf_simple, :media_removal], [])
|
clear_config([:mrf_simple, :media_removal], [])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
||||||
|
assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "has a matching host" do
|
test "has a matching host" do
|
||||||
clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
|
clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) ==
|
assert SimplePolicy.filter(media_message) ==
|
||||||
|
@ -42,12 +45,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
media_message
|
media_message
|
||||||
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(media_update_message) ==
|
||||||
|
{:ok,
|
||||||
|
media_update_message
|
||||||
|
|> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
|
||||||
|
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "match with wildcard domain" do
|
test "match with wildcard domain" do
|
||||||
clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
|
clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) ==
|
assert SimplePolicy.filter(media_message) ==
|
||||||
|
@ -55,6 +64,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
media_message
|
media_message
|
||||||
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(media_update_message) ==
|
||||||
|
{:ok,
|
||||||
|
media_update_message
|
||||||
|
|> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
|
||||||
|
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -63,31 +77,41 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
test "is empty" do
|
test "is empty" do
|
||||||
clear_config([:mrf_simple, :media_nsfw], [])
|
clear_config([:mrf_simple, :media_nsfw], [])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
||||||
|
assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "has a matching host" do
|
test "has a matching host" do
|
||||||
clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
|
clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) ==
|
assert SimplePolicy.filter(media_message) ==
|
||||||
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(media_update_message) ==
|
||||||
|
{:ok, put_in(media_update_message, ["object", "sensitive"], true)}
|
||||||
|
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "match with wildcard domain" do
|
test "match with wildcard domain" do
|
||||||
clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
|
clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
|
||||||
media_message = build_media_message()
|
media_message = build_media_message()
|
||||||
|
media_update_message = build_media_update_message()
|
||||||
local_message = build_local_message()
|
local_message = build_local_message()
|
||||||
|
|
||||||
assert SimplePolicy.filter(media_message) ==
|
assert SimplePolicy.filter(media_message) ==
|
||||||
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(media_update_message) ==
|
||||||
|
{:ok, put_in(media_update_message, ["object", "sensitive"], true)}
|
||||||
|
|
||||||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -104,6 +128,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp build_media_update_message do
|
||||||
|
%{
|
||||||
|
"actor" => "https://remote.instance/users/bob",
|
||||||
|
"type" => "Update",
|
||||||
|
"object" => %{
|
||||||
|
"attachment" => [%{}],
|
||||||
|
"tag" => ["foo"],
|
||||||
|
"sensitive" => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
describe "when :report_removal" do
|
describe "when :report_removal" do
|
||||||
test "is empty" do
|
test "is empty" do
|
||||||
clear_config([:mrf_simple, :report_removal], [])
|
clear_config([:mrf_simple, :report_removal], [])
|
||||||
|
|
Loading…
Reference in a new issue