Add my custom MRFs
This commit is contained in:
parent
a8f3cf6563
commit
cbc0a66766
4 changed files with 293 additions and 0 deletions
69
lib/pleroma/web/activity_pub/mrf/block_notification.ex
Normal file
69
lib/pleroma/web/activity_pub/mrf/block_notification.ex
Normal file
|
@ -0,0 +1,69 @@
|
|||
# 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.BlockNotification do
|
||||
@moduledoc "Notify local users upon remote block."
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
defp is_block_or_unblock(%{"type" => "Block", "object" => object}),
|
||||
do: {true, "blocked", object}
|
||||
|
||||
defp is_block_or_unblock(%{
|
||||
"type" => "Undo",
|
||||
"object" => %{"type" => "Block", "object" => object}
|
||||
}),
|
||||
do: {true, "unblocked", object}
|
||||
|
||||
defp is_block_or_unblock(_), do: {false, nil, nil}
|
||||
|
||||
defp is_remote_or_displaying_local?(%User{local: false}), do: true
|
||||
|
||||
defp is_remote_or_displaying_local?(_), do: true
|
||||
|
||||
@impl true
|
||||
def filter(message) do
|
||||
|
||||
with {true, action, object} <- is_block_or_unblock(message),
|
||||
%User{} = actor <- User.get_cached_by_ap_id(message["actor"]),
|
||||
%User{} = recipient <- User.get_cached_by_ap_id(object),
|
||||
true <- recipient.local,
|
||||
true <- is_remote_or_displaying_local?(actor),
|
||||
false <- User.blocks_user?(recipient, actor) do
|
||||
|
||||
# Create /opt/pleroma/logs/ with write perms for user pleroma
|
||||
# Make a cron job to delete the log file every hour or whatever
|
||||
# Not my problem
|
||||
log_file = "/opt/pleroma/logs/blocks.log"
|
||||
bot_user = "cockblock"
|
||||
|
||||
log_contents = if File.exists?(log_file) do
|
||||
File.read!(log_file)
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
logged_blocks = String.split(log_contents, "\n")
|
||||
|
||||
actor_name = (fn actor_uri -> Path.basename(actor_uri.path) <> "@" <> actor_uri.authority end).(URI.parse(message["actor"]))
|
||||
log_entry = actor_name <> ":" <> action
|
||||
|
||||
unless Enum.member?(logged_blocks, log_entry) do
|
||||
File.write!(log_file, log_entry <> "\n", [:append])
|
||||
_reply =
|
||||
CommonAPI.post(User.get_by_nickname(bot_user), %{
|
||||
status: "@" <> recipient.nickname <> " you have been " <> action <> " by @" <> actor_name <> " (" <> actor_name <> ")",
|
||||
visibility: "unlisted"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
{:ok, message}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
47
lib/pleroma/web/activity_pub/mrf/change_react_to_like.ex
Normal file
47
lib/pleroma/web/activity_pub/mrf/change_react_to_like.ex
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.ChangeReactstoLikes do
|
||||
require Logger
|
||||
|
||||
@moduledoc "Changes specified EmojiReacts into a Like"
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp is_remote(host) do
|
||||
my_host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
|
||||
my_host != host
|
||||
end
|
||||
|
||||
@impl true
|
||||
@spec filter(any) :: {:ok, any}
|
||||
def filter(%{"type" => "EmojiReact"} = object) do
|
||||
actor = object["actor"]
|
||||
host = URI.parse(actor).host
|
||||
|
||||
if is_remote(host) do
|
||||
react = object["content"]
|
||||
|
||||
# TODO: make this pull from config
|
||||
if react in ["👍", "👎", "❤️", "😆", "😮", "😢", "😩", "😭", "🔥", "⭐"] do
|
||||
Logger.info("MRF.ChangeReactstoLikes: Changing #{inspect(react)} to a Like")
|
||||
|
||||
object =
|
||||
object
|
||||
|> Map.put("type", "Like")
|
||||
|
||||
{:ok, object}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
148
lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
Normal file
148
lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
Normal file
|
@ -0,0 +1,148 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|
||||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp do_extract({:a, attrs, _}, acc) do
|
||||
if Enum.find(attrs, fn {name, value} ->
|
||||
name == "class" && value in ["mention", "u-url mention", "mention u-url"]
|
||||
end) do
|
||||
href = Enum.find(attrs, fn {name, _} -> name == "href" end) |> elem(1)
|
||||
acc ++ [href]
|
||||
else
|
||||
acc
|
||||
end
|
||||
end
|
||||
|
||||
defp do_extract({_, _, children}, acc) do
|
||||
do_extract(children, acc)
|
||||
end
|
||||
|
||||
defp do_extract(nodes, acc) when is_list(nodes) do
|
||||
Enum.reduce(nodes, acc, fn node, acc -> do_extract(node, acc) end)
|
||||
end
|
||||
|
||||
defp do_extract(_, acc), do: acc
|
||||
|
||||
defp extract_mention_uris_from_content(content) do
|
||||
{:ok, tree} = :fast_html.decode(content, format: [:html_atoms])
|
||||
do_extract(tree, [])
|
||||
end
|
||||
|
||||
defp get_replied_to_user(%{"inReplyTo" => in_reply_to}) do
|
||||
case Object.normalize(in_reply_to, fetch: false) do
|
||||
%Object{data: %{"actor" => actor}} -> User.get_cached_by_ap_id(actor)
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp get_replied_to_user(_object), do: nil
|
||||
|
||||
# Ensure the replied-to user is sorted to the left
|
||||
defp sort_replied_user([%User{id: user_id} | _] = users, %User{id: user_id}), do: users
|
||||
|
||||
defp sort_replied_user(users, %User{id: user_id} = user) do
|
||||
if Enum.find(users, fn u -> u.id == user_id end) do
|
||||
users = Enum.reject(users, fn u -> u.id == user_id end)
|
||||
[user | users]
|
||||
else
|
||||
users
|
||||
end
|
||||
end
|
||||
|
||||
defp sort_replied_user(users, _), do: users
|
||||
|
||||
# Drop constants and the actor's own AP ID
|
||||
defp clean_recipients(recipients, object) do
|
||||
Enum.reject(recipients, fn ap_id ->
|
||||
ap_id in [
|
||||
object["object"]["actor"],
|
||||
Pleroma.Constants.as_public(),
|
||||
Pleroma.Web.ActivityPub.Utils.as_local_public()
|
||||
]
|
||||
end)
|
||||
end
|
||||
|
||||
defp is_remote(host) do
|
||||
my_host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
|
||||
my_host != host
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(
|
||||
%{
|
||||
"type" => "Create",
|
||||
"object" => %{"type" => "Note", "to" => to, "inReplyTo" => in_reply_to}
|
||||
} = object
|
||||
)
|
||||
when is_list(to) and is_binary(in_reply_to) do
|
||||
actor = object["object"]["actor"]
|
||||
host = URI.parse(actor).host
|
||||
|
||||
if is_remote(host) do
|
||||
# image-only posts from pleroma apparently reach this MRF without the content field
|
||||
content = object["object"]["content"] || ""
|
||||
|
||||
# Get the replied-to user for sorting
|
||||
replied_to_user = get_replied_to_user(object["object"])
|
||||
|
||||
mention_users =
|
||||
to
|
||||
|> clean_recipients(object)
|
||||
|> Enum.map(&User.get_cached_by_ap_id/1)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> sort_replied_user(replied_to_user)
|
||||
|
||||
explicitly_mentioned_uris = extract_mention_uris_from_content(content)
|
||||
|
||||
if Enum.empty?(explicitly_mentioned_uris) do
|
||||
added_mentions =
|
||||
Enum.reduce(mention_users, "", fn %User{ap_id: uri} = user, acc ->
|
||||
unless uri in explicitly_mentioned_uris do
|
||||
acc <> Formatter.mention_from_user(user, %{mentions_format: :compact}) <> " "
|
||||
else
|
||||
acc
|
||||
end
|
||||
end)
|
||||
|
||||
recipients_inline =
|
||||
if added_mentions != "",
|
||||
do: "<span class=\"recipients-inline\">#{added_mentions}</span>",
|
||||
else: ""
|
||||
|
||||
content =
|
||||
cond do
|
||||
# For Markdown posts, insert the mentions inside the first <p> tag
|
||||
recipients_inline != "" && String.starts_with?(content, "<p>") ->
|
||||
"<p>" <> recipients_inline <> String.trim_leading(content, "<p>")
|
||||
|
||||
recipients_inline != "" ->
|
||||
recipients_inline <> content
|
||||
|
||||
true ->
|
||||
content
|
||||
end
|
||||
|
||||
{:ok, put_in(object["object"]["content"], content)}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
29
lib/pleroma/web/activity_pub/mrf/no_incoming_deletes.ex
Normal file
29
lib/pleroma/web/activity_pub/mrf/no_incoming_deletes.ex
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.NoIncomingDeletes do
|
||||
@moduledoc "Reject remote deletes."
|
||||
|
||||
require Logger
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
||||
actor_info = URI.parse(actor)
|
||||
instance_domain = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
|
||||
if (actor_info.host == instance_domain) do
|
||||
Logger.warn("DELETE from this instance, not rejecting: #{inspect(object)}")
|
||||
{:ok, object}
|
||||
else
|
||||
Logger.warn("DELETE rejected: #{inspect(object)}")
|
||||
{:reject, object}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
Loading…
Reference in a new issue