forked from AkkomaGang/akkoma
1f863f0a36
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
165 lines
4.5 KiB
Elixir
165 lines
4.5 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.TagPolicy do
|
|
alias Pleroma.User
|
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
|
@moduledoc """
|
|
Apply policies based on user tags
|
|
|
|
This policy applies policies on a user activities depending on their tags
|
|
on your instance.
|
|
|
|
- `mrf_tag:media-force-nsfw`: Mark as sensitive on presence of attachments
|
|
- `mrf_tag:media-strip`: Remove attachments
|
|
- `mrf_tag:force-unlisted`: Mark as unlisted (removes from the federated timeline)
|
|
- `mrf_tag:sandbox`: Remove from public (local and federated) timelines
|
|
- `mrf_tag:disable-remote-subscription`: Reject non-local follow requests
|
|
- `mrf_tag:disable-any-subscription`: Reject any follow requests
|
|
"""
|
|
|
|
require Pleroma.Constants
|
|
|
|
defp get_tags(%User{tags: tags}) when is_list(tags), do: tags
|
|
defp get_tags(_), do: []
|
|
|
|
defp process_tag(
|
|
"mrf_tag:media-force-nsfw",
|
|
%{
|
|
"type" => type,
|
|
"object" => %{"attachment" => child_attachment}
|
|
} = message
|
|
)
|
|
when length(child_attachment) > 0 and type in ["Create", "Update"] do
|
|
{:ok, Kernel.put_in(message, ["object", "sensitive"], true)}
|
|
end
|
|
|
|
defp process_tag(
|
|
"mrf_tag:media-strip",
|
|
%{
|
|
"type" => type,
|
|
"object" => %{"attachment" => child_attachment} = object
|
|
} = message
|
|
)
|
|
when length(child_attachment) > 0 and type in ["Create", "Update"] do
|
|
object = Map.delete(object, "attachment")
|
|
message = Map.put(message, "object", object)
|
|
|
|
{:ok, message}
|
|
end
|
|
|
|
defp process_tag(
|
|
"mrf_tag:force-unlisted",
|
|
%{
|
|
"type" => type,
|
|
"to" => to,
|
|
"cc" => cc,
|
|
"actor" => actor,
|
|
"object" => object
|
|
} = message
|
|
)
|
|
when type in ["Create", "Update"] do
|
|
user = User.get_cached_by_ap_id(actor)
|
|
|
|
if Enum.member?(to, Pleroma.Constants.as_public()) do
|
|
to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
|
|
cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
|
|
|
|
object =
|
|
object
|
|
|> Map.put("to", to)
|
|
|> Map.put("cc", cc)
|
|
|
|
message =
|
|
message
|
|
|> Map.put("to", to)
|
|
|> Map.put("cc", cc)
|
|
|> Map.put("object", object)
|
|
|
|
{:ok, message}
|
|
else
|
|
{:ok, message}
|
|
end
|
|
end
|
|
|
|
defp process_tag(
|
|
"mrf_tag:sandbox",
|
|
%{
|
|
"type" => type,
|
|
"to" => to,
|
|
"cc" => cc,
|
|
"actor" => actor,
|
|
"object" => object
|
|
} = message
|
|
)
|
|
when type in ["Create", "Update"] do
|
|
user = User.get_cached_by_ap_id(actor)
|
|
|
|
if Enum.member?(to, Pleroma.Constants.as_public()) or
|
|
Enum.member?(cc, Pleroma.Constants.as_public()) do
|
|
to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
|
|
cc = List.delete(cc, Pleroma.Constants.as_public())
|
|
|
|
object =
|
|
object
|
|
|> Map.put("to", to)
|
|
|> Map.put("cc", cc)
|
|
|
|
message =
|
|
message
|
|
|> Map.put("to", to)
|
|
|> Map.put("cc", cc)
|
|
|> Map.put("object", object)
|
|
|
|
{:ok, message}
|
|
else
|
|
{:ok, message}
|
|
end
|
|
end
|
|
|
|
defp process_tag(
|
|
"mrf_tag:disable-remote-subscription",
|
|
%{"type" => "Follow", "actor" => actor} = message
|
|
) do
|
|
user = User.get_cached_by_ap_id(actor)
|
|
|
|
if user.local == true do
|
|
{:ok, message}
|
|
else
|
|
{:reject,
|
|
"[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"}
|
|
end
|
|
end
|
|
|
|
defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}),
|
|
do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"}
|
|
|
|
defp process_tag(_, message), do: {:ok, message}
|
|
|
|
def filter_message(actor, message) do
|
|
User.get_cached_by_ap_id(actor)
|
|
|> get_tags()
|
|
|> Enum.reduce({:ok, message}, fn
|
|
tag, {:ok, message} ->
|
|
process_tag(tag, message)
|
|
|
|
_, error ->
|
|
error
|
|
end)
|
|
end
|
|
|
|
@impl true
|
|
def filter(%{"object" => target_actor, "type" => "Follow"} = message),
|
|
do: filter_message(target_actor, message)
|
|
|
|
@impl true
|
|
def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"],
|
|
do: filter_message(actor, message)
|
|
|
|
@impl true
|
|
def filter(message), do: {:ok, message}
|
|
|
|
@impl true
|
|
def describe, do: {:ok, %{}}
|
|
end
|