diff options
| author | dcc <dcc@logografos.com> | 2023-09-02 00:52:52 -0700 |
|---|---|---|
| committer | dcc <dcc@logografos.com> | 2023-09-02 00:52:52 -0700 |
| commit | 3a4773c3c2bd0bbef244eb519b07208da9108e49 (patch) | |
| tree | 973567a6f3abb37bfb0f785b1cad14ed55840ef5 /static/modules | |
| download | anni-3a4773c3c2bd0bbef244eb519b07208da9108e49.tar.gz anni-3a4773c3c2bd0bbef244eb519b07208da9108e49.tar.bz2 anni-3a4773c3c2bd0bbef244eb519b07208da9108e49.zip | |
First
Diffstat (limited to 'static/modules')
| -rw-r--r-- | static/modules/emoji_reactions_are_retarded.ex | 26 | ||||
| -rw-r--r-- | static/modules/high_roller_policy.ex | 339 | ||||
| -rw-r--r-- | static/modules/no_incoming_deletes.ex | 24 |
3 files changed, 389 insertions, 0 deletions
diff --git a/static/modules/emoji_reactions_are_retarded.ex b/static/modules/emoji_reactions_are_retarded.ex new file mode 100644 index 0000000..91884c3 --- /dev/null +++ b/static/modules/emoji_reactions_are_retarded.ex @@ -0,0 +1,26 @@ +# The second I figure out how to get this out of the UI, that's gone too. +# What the hell is this, fucking Github? Facebook? +# Fuck EmojiReaction. Fuck it completely. +# ...Unless it lets you use the custom emojis (which are fun) instead of +# the stupid Unicode Consortium ones (which are terrible), in which case +# I'll get rid of this policy. +defmodule Pleroma.Web.ActivityPub.MRF.EmojiReactionsAreRetarded do + require Logger + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + @impl true + def filter(%{"type" => "EmojiReact"} = message) do + Logger.info("FUCK EMOJI REACTIONS: #{inspect(message)}") + message = message + |> Map.put("type", "Like") + |> Map.drop(["content"]) + #{:reject, message} + {:ok, message} + end + + @impl true + def filter(object), do: {:ok, object} + + @impl true + def describe, do: {:ok, %{}} +end diff --git a/static/modules/high_roller_policy.ex b/static/modules/high_roller_policy.ex new file mode 100644 index 0000000..50b21ea --- /dev/null +++ b/static/modules/high_roller_policy.ex @@ -0,0 +1,339 @@ +# Three-in-one policy for block, report and unfollow notifications. +# Credits for the individual parts: +# Yukkuri for the combined block/report MRF +# https://gitlab.eientei.org/eientei/pleroma/-/blob/eientei/lib/pleroma/web/activity_pub/mrf/block_bot_policy.ex +# NEETzsche for the block MRF with configurable message +# https://gitlab.com/soapbox-pub/rebased/-/blob/develop/lib/pleroma/web/activity_pub/mrf/block_notification_policy.ex +# Nekobit for the unfollow MRF (nigga nuked his account at the time, linking cached version) +# https://eientei.org/notice/AL6nnjih8H6Lco8QoS +# Pete for the example of Cachex-based rate limiting +# https://freespeechextremist.com/objects/9f24a3e4-2e34-4fcb-a0d1-42229e27da3e + +defmodule Pleroma.Web.ActivityPub.MRF.HighRollerPolicy do + alias Pleroma.User + alias Pleroma.Web.CommonAPI + alias Pleroma.Config + + require Logger + + @moduledoc "Notify local users upon the block, report or unfollow." + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + 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_report(%{"type" => "Flag", "object" => objects}) do + case objects do + [head | tail] when is_binary(head) -> {true, tail, head} + s when is_binary(s) -> {true, [], s} + _ -> {true, [], nil} + end + end + + defp is_report(_), do: {false, [], nil} + + defp extract_reported_post(post) do + case post do + %{"id" => id} -> id + s when is_binary(s) -> s + _ -> nil + end + end + + defp is_unfollow(%{ + "type" => "Undo", + "object" => %{"type" => "Follow", "object" => object} + }), + do: {true, object} + + defp is_unfollow(_), do: {false, nil, nil} + + @impl true + def filter(message) do + with {:error, _} <- Cachex.stats(:highroller), do: Cachex.start(:highroller, [ stats: true ]) + systime = :os.system_time(:seconds) + + 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), + false <- Enum.member?(Config.get([:mrf_high_roller, :actor_blacklist]), message["actor"]), + false <- Enum.member?(Config.get([:mrf_high_roller, :domain_blacklist]), URI.parse(message["actor"]).host), + true <- recipient.local do + + {_, actiontime} = Cachex.fetch(:highroller, actor.nickname<>","<>recipient.nickname<>","<>action, fn(_i) -> {:commit, :os.system_time(:seconds)-1} end) + {_, globalcount} = Cachex.fetch(:highroller, "global:"<>actor.nickname, fn(_i) -> {:commit, 0} end) + + blocker = if(Config.get([:mrf_high_roller, :tag_blocking_actor]) && !Enum.member?(Config.get([:mrf_high_roller, :domain_greylist]), URI.parse(message["actor"]).host)) do + "@" <> actor.nickname + else + actor.nickname + end + + replacements = %{ + "actor" => blocker, + "target" => "@" <> recipient.nickname, + "action" => action + } + + msg = + Regex.replace( + ~r/{([a-z]+)?}/, + Config.get([:mrf_high_roller, :block_message]), + fn _, match -> + replacements[match] + end + ) + + if (systime > actiontime && globalcount < Config.get([:mrf_high_roller, :global_threshold])) do + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.put(:highroller, actor.nickname<>","<>recipient.nickname<>","<>action, systime+Config.get([:mrf_high_roller, :timeout])) + CommonAPI.post(User.get_cached_by_nickname(Config.get([:mrf_high_roller, :user])), %{ + status: msg, + visibility: Config.get([:mrf_high_roller, :block_visibility]) + }) + else + Logger.warn("Rate-limited incoming block notif! #{inspect(message)}") + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.incr(:highroller, actor.nickname<>","<>recipient.nickname<>","<>action, 30*(1+(systime-actiontime))) + end + end + + with {true, objects, to} <- is_report(message), + %User{} = actor <- User.get_cached_by_ap_id(message["actor"]), + %User{} = recipient <- User.get_cached_by_ap_id(to), + false <- Enum.member?(Config.get([:mrf_high_roller, :actor_blacklist]), message["actor"]), + false <- Enum.member?(Config.get([:mrf_high_roller, :domain_blacklist]), URI.parse(message["actor"]).host), + true <- recipient.local do + + {_, actiontime} = Cachex.fetch(:highroller, actor.nickname<>","<>recipient.nickname<>",report", fn(_i) -> {:commit, :os.system_time(:seconds)-1} end) + {_, globalcount} = Cachex.fetch(:highroller, "global:"<>actor.nickname, fn(_i) -> {:commit, 0} end) + + reporter = if(Config.get([:mrf_high_roller, :tag_reporting_actor]) && !Enum.member?(Config.get([:mrf_high_roller, :domain_greylist]), URI.parse(message["actor"]).host)) do + "@" <> actor.nickname + else + actor.nickname + end + + replacements = %{ + "actor" => reporter, + "target" => "@" <> recipient.nickname + } + + msg = + Regex.replace( + ~r/{([a-z]+)?}/, + Pleroma.Config.get([:mrf_high_roller, :report_message]), + fn _, match -> + replacements[match] + end + ) + + posts = + objects + |> Enum.map(&extract_reported_post/1) + |> Enum.reject(&is_nil/1) + |> Enum.map(fn s -> "- " <> s end) + |> Enum.join("\n") + |> (fn s -> + case s do + "" -> "" + s -> "\n\nReported objects:\n" <> s + end + end).() + + comment = + case message["content"] do + "" -> "" + s when is_binary(s) -> "\n\nReport message:\n" <> s + _ -> "" + end + + if (systime > actiontime && globalcount < Config.get([:mrf_high_roller, :global_threshold])) do + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.put(:highroller, actor.nickname<>","<>recipient.nickname<>",report", systime+Config.get([:mrf_high_roller, :timeout])) + CommonAPI.post(User.get_cached_by_nickname(Config.get([:mrf_high_roller, :user])), %{ + status: msg <> comment <> posts, + visibility: Config.get([:mrf_high_roller, :report_visibility]) + }) + else + Logger.warn("Rate-limited incoming report notif! #{inspect(message)}") + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.incr(:highroller, actor.nickname<>","<>recipient.nickname<>",report", 30*(1+(systime-actiontime))) + end + end + + with {true, object} <- is_unfollow(message), + %User{} = actor <- User.get_cached_by_ap_id(message["actor"]), + %User{} = recipient <- User.get_cached_by_ap_id(object), + false <- Enum.member?(Config.get([:mrf_high_roller, :actor_blacklist]), message["actor"]), + false <- Enum.member?(Config.get([:mrf_high_roller, :domain_blacklist]), URI.parse(message["actor"]).host), + true <- recipient.local do + + {_, actiontime} = Cachex.fetch(:highroller, actor.nickname<>","<>recipient.nickname<>",unfollow", fn(_i) -> {:commit, :os.system_time(:seconds)-1} end) + {_, globalcount} = Cachex.fetch(:highroller, "global:"<>actor.nickname, fn(_i) -> {:commit, 0} end) + + unfollower = if(Config.get([:mrf_high_roller, :tag_unfollowing_actor]) && !Enum.member?(Config.get([:mrf_high_roller, :domain_greylist]), URI.parse(message["actor"]).host)) do + "@" <> actor.nickname + else + actor.nickname + end + + replacements = %{ + "actor" => unfollower, + "target" => "@" <> recipient.nickname + } + + msg = + Regex.replace( + ~r/{([a-z]+)?}/, + Pleroma.Config.get([:mrf_high_roller, :unfollow_message]), + fn _, match -> + replacements[match] + end + ) + + if (systime > actiontime && globalcount < Config.get([:mrf_high_roller, :global_threshold])) do + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.put(:highroller, actor.nickname<>","<>recipient.nickname<>",unfollow", systime+Config.get([:mrf_high_roller, :timeout])) + CommonAPI.post(User.get_cached_by_nickname(Config.get([:mrf_high_roller, :user])), %{ + status: msg, + visibility: Config.get([:mrf_high_roller, :unfollow_visibility]) + }) + else + Logger.warn("Rate-limited incoming unfollow notif! #{inspect(message)}") + Cachex.incr(:highroller, "global:"<>actor.nickname, globalcount+1) + Cachex.incr(:highroller, actor.nickname<>","<>recipient.nickname<>",unfollow", 30*(1+(systime-actiontime))) + end + end + + {:ok, message} + end + + @impl true + def config_description do + %{ + key: :mrf_high_roller, + related_policy: "Pleroma.Web.ActivityPub.MRF.HighRollerPolicy", + label: "High Roller Policy", + description: "Three-in-one policy for notifying users upon being blocked, unfollowed or reported", + children: [ + %{ + key: :user, + type: :string, + label: "Account", + description: "Account from which notifications would be sent", + suggestions: ["blockbot"] + }, + %{ + key: :timeout, + type: :integer, + label: "Timeout", + description: "Timeout (in seconds) between which no new notifications of the same type can be sent", + suggestions: [60] + }, + %{ + key: :global_threshold, + type: :integer, + label: "Global threshold", + description: "Global threshold of the actions for the actor", + suggestions: [5] + }, + %{ + key: :actor_blacklist, + type: {:list, :string}, + label: "Actor blacklist", + description: "List of actors to skip sending a notification about", + suggestions: ["https://freespeechextremist.com/users/p"] + }, + %{ + key: :domain_greylist, + type: {:list, :string}, + label: "Domain greylist", + description: "List of domains to exclude their users from being tagged", + suggestions: ["freespeechextremist.com"] + }, + %{ + key: :domain_blacklist, + type: {:list, :string}, + label: "Domain blacklist", + description: "List of domains to skip sending a notification about", + suggestions: ["freespeechextremist.com"] + }, + %{ + key: :block_message, + type: :string, + label: "Block message", + description: + "The message to send when someone is blocked or unblocked; use {actor}, {target}, and {action} variables", + suggestions: ["{target} you have been {action} by {actor}"] + }, + %{ + key: :tag_blocking_actor, + type: :boolean, + label: "Tag blocking actor", + description: "Whether to tag the blocking actor or not" + }, + %{ + key: :block_visibility, + type: :string, + label: "Block visibility", + description: "Visibility of the block notification", + suggestions: ["public", "unlisted", "private", "direct"] + }, + %{ + key: :report_message, + type: :string, + label: "Report message", + description: + "The message to send when someone is reported; use {actor} and {target} variables", + suggestions: ["{target} you have been reported by {actor}"] + }, + %{ + key: :tag_reporting_actor, + type: :boolean, + label: "Tag reporting actor", + description: "Whether to tag the reporting actor or not" + }, + %{ + key: :report_visibility, + type: :string, + label: "Report visibility", + description: "Visibility of the report notification", + suggestions: ["public", "unlisted", "private", "direct"] + }, + %{ + key: :unfollow_message, + type: :string, + label: "Unfollow message", + description: + "The message to send when someone is unfollowed; use {actor} and {target} variables", + suggestions: ["{target} you have been unfollowed by {actor}"] + }, + %{ + key: :tag_unfollowing_actor, + type: :boolean, + label: "Tag unfollowing actor", + description: "Whether to tag the unfollowing actor or not" + }, + %{ + key: :unfollow_visibility, + type: :string, + label: "Unfollow visibility", + description: "Visibility of the unfollow notification", + suggestions: ["public", "unlisted", "private", "direct"] + } + ] + } + end + + @impl true + def describe, do: {:ok, %{}} +end diff --git a/static/modules/no_incoming_deletes.ex b/static/modules/no_incoming_deletes.ex new file mode 100644 index 0000000..0c5d9e7 --- /dev/null +++ b/static/modules/no_incoming_deletes.ex @@ -0,0 +1,24 @@ +# THE "CLOUD" IS JUST SOMEONE ELSE'S COMPUTER +# have we been using the same internet? +defmodule Pleroma.Web.ActivityPub.MRF.NoIncomingDeletes do + require Logger + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + @impl true + def filter(%{"type" => "Delete", "actor" => actor} = object) do + actor_info = URI.parse(actor) + if(actor_info.host == "annihilation.social") do + Logger.warn("DELETE from ANNI, 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 |
