1f863f0a36
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
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
61 lines
1.7 KiB
Elixir
61 lines
1.7 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
|
alias Pleroma.User
|
|
|
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
|
|
|
require Logger
|
|
|
|
@impl true
|
|
def history_awareness, do: :auto
|
|
|
|
# has the user successfully posted before?
|
|
defp old_user?(%User{} = u) do
|
|
u.note_count > 0 || u.follower_count > 0
|
|
end
|
|
|
|
# does the post contain links?
|
|
defp contains_links?(%{"content" => content} = _object) do
|
|
content
|
|
|> Floki.parse_fragment!()
|
|
|> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"],a.zrl")
|
|
|> Floki.attribute("a", "href")
|
|
|> length() > 0
|
|
end
|
|
|
|
defp contains_links?(_), do: false
|
|
|
|
@impl true
|
|
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),
|
|
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
|
{:old_user, true} <- {:old_user, old_user?(u)} do
|
|
{:ok, message}
|
|
else
|
|
{:ok, %User{local: true}} ->
|
|
{:ok, message}
|
|
|
|
{:contains_links, false} ->
|
|
{:ok, message}
|
|
|
|
{:old_user, false} ->
|
|
{:reject, "[AntiLinkSpamPolicy] User has no posts nor followers"}
|
|
|
|
{:error, _} ->
|
|
{:reject, "[AntiLinkSpamPolicy] Failed to get or fetch user by ap_id"}
|
|
|
|
e ->
|
|
{:reject, "[AntiLinkSpamPolicy] Unhandled error #{inspect(e)}"}
|
|
end
|
|
end
|
|
|
|
# in all other cases, pass through
|
|
def filter(message), do: {:ok, message}
|
|
|
|
@impl true
|
|
def describe, do: {:ok, %{}}
|
|
end
|