diff --git a/CHANGELOG.md b/CHANGELOG.md index df34d2bb6..183a60d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - support for fedibird-fe, and non-breaking API parity for it to function - support for setting instance languages in metadata - support for reusing oauth tokens, and not requiring new authorizations +- the ability to obfuscate domains in your MRF descriptions ### Changed - MFM parsing is now done on the backend by a modified version of ilja's parser -> https://akkoma.dev/AkkomaGang/mfm-parser diff --git a/config/config.exs b/config/config.exs index ec82e872a..5ae7a33a2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -794,7 +794,8 @@ config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false config :pleroma, :mrf, policies: [Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy, Pleroma.Web.ActivityPub.MRF.TagPolicy], transparency: true, - transparency_exclusions: [] + transparency_exclusions: [], + transparency_obfuscate_domains: [] config :ex_aws, http_client: Pleroma.HTTP.ExAws diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 8fa188de1..a29db208c 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -120,6 +120,7 @@ To add configuration to your config file, you can copy it from the base config. * `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)). * `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). * `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. +* `transparency_obfuscate_domains`: Show domains with `*` in the middle, to censor them if needed. For example, `ridingho.me` will show as `rid*****.me` ## Federation ### MRF policies diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index bd6f6777f..5606dac83 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -41,6 +41,16 @@ defmodule Pleroma.Web.ActivityPub.MRF do suggestions: [ "exclusion.com" ] + }, + %{ + key: :transparency_obfuscate_domains, + label: "MRF domain obfuscation", + type: {:list, :string}, + description: + "Obfuscate domains in MRF transparency. This is useful if the domain you're blocking contains words you don't want displayed, but still want to disclose the MRF settings.", + suggestions: [ + "badword.com" + ] } ] } diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index c631cc85f..415c5d2dd 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -256,10 +256,35 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do def filter(object), do: {:ok, object} + defp obfuscate(string) when is_binary(string) do + string + |> to_charlist() + |> Enum.with_index() + |> Enum.map(fn + {?., _index} -> + ?. + + {char, index} -> + if 3 <= index && index < String.length(string) - 3, do: ?*, else: char + end) + |> to_string() + end + + defp maybe_obfuscate(host, obfuscations) do + if MRF.subdomain_match?(obfuscations, host) do + obfuscate(host) + else + host + end + end + @impl true def describe do exclusions = Config.get([:mrf, :transparency_exclusions]) |> MRF.instance_list_from_tuples() + obfuscations = + Config.get([:mrf, :transparency_obfuscate_domains], []) |> MRF.subdomains_regex() + mrf_simple_excluded = Config.get(:mrf_simple) |> Enum.map(fn {rule, instances} -> @@ -269,7 +294,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do mrf_simple = mrf_simple_excluded |> Enum.map(fn {rule, instances} -> - {rule, Enum.map(instances, fn {host, _} -> host end)} + {rule, Enum.map(instances, fn {host, _} -> maybe_obfuscate(host, obfuscations) end)} end) |> Map.new() @@ -286,7 +311,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do |> Enum.map(fn {rule, instances} -> instances = instances - |> Enum.map(fn {host, reason} -> {host, %{"reason" => reason}} end) + |> Enum.map(fn {host, reason} -> + {maybe_obfuscate(host, obfuscations), %{"reason" => reason}} + end) |> Map.new() {rule, instances} diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 0a0f51bdb..0569bfed3 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -216,6 +216,43 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end end + describe "describe/1" do + test "returns a description of the policy" do + clear_config([:mrf_simple, :reject], [ + {"remote.instance", "did not give my catboy a burg"} + ]) + + assert {:ok, %{mrf_simple: %{reject: ["remote.instance"]}}} = SimplePolicy.describe() + end + + test "excludes domains listed in :transparency_exclusions" do + clear_config([:mrf, :transparency_exclusions], [{"remote.instance", ":("}]) + + clear_config([:mrf_simple, :reject], [ + {"remote.instance", "did not give my catboy a burg"} + ]) + + {:ok, description} = SimplePolicy.describe() + assert %{mrf_simple: %{reject: []}} = description + assert description[:mrf_simple_info][:reject] == nil + end + + test "obfuscates domains listed in :transparency_obfuscate_domains" do + clear_config([:mrf, :transparency_obfuscate_domains], ["remote.instance", "a.b"]) + + clear_config([:mrf_simple, :reject], [ + {"remote.instance", "did not give my catboy a burg"}, + {"a.b", "spam-poked me on facebook in 2006"} + ]) + + assert {:ok, + %{ + mrf_simple: %{reject: ["rem***.*****nce", "a.b"]}, + mrf_simple_info: %{reject: %{"rem***.*****nce" => %{}}} + }} = SimplePolicy.describe() + end + end + defp build_ftl_actor_and_message do actor = insert(:user)