Fix regex usage in MRF (#254)
authorfloatingghost <hannah@coffee-and-dreams.uk>
Sun, 6 Nov 2022 23:50:32 +0000 (23:50 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Sun, 6 Nov 2022 23:50:32 +0000 (23:50 +0000)
fixes #235
fixes #228

Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/254

CHANGELOG.md
lib/pleroma/web/activity_pub/mrf.ex
test/pleroma/user_test.exs
test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
test/pleroma/web/activity_pub/mrf_test.exs

index 6bc87ada1f87f6f2684cc2055f67c94beb697b54..05d24a8219895aa6690f833d8e174fa35d53fbb6 100644 (file)
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## Unreleased
 
+## UPGRADE NOTES
+- Change your instance blocks to remove any `*.` prefixes. `example.com` will block `*.example.com` by default now
+
 ## Added
 - Officially supported docker release
 - Ability to remove followers unilaterally without a block
@@ -14,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ## Changes
 - Follows no longer override domain blocks, a domain block is final
 - Deletes are now the lowest priority to publish and will be handled after creates
+- Domain blocks are now subdomain-matches by default
 
 ## Fixed
 - Registrations via ldap are now compatible with the latest OTP24
index 4df226e80eb09de8754e8bb55e69c6a1f3b6362f..7b7f446468e7f377107d9391a99b116dfb16b878 100644 (file)
@@ -149,9 +149,18 @@ defmodule Pleroma.Web.ActivityPub.MRF do
   defp get_policies(policies) when is_list(policies), do: policies
   defp get_policies(_), do: []
 
+  # Matches the following:
+  # - https://baddomain.net
+  # - https://extra.baddomain.net/
+  # Does NOT match the following:
+  # - https://maybebaddomain.net/
+  def subdomain_regex(domain) do
+    ~r/^(.+\.)?#{Regex.escape(domain)}$/i
+  end
+
   @spec subdomains_regex([String.t()]) :: [Regex.t()]
   def subdomains_regex(domains) when is_list(domains) do
-    for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i
+    Enum.map(domains, &subdomain_regex/1)
   end
 
   @spec subdomain_match?([Regex.t()], String.t()) :: boolean()
index f11aec1364f2ae1d2256a39e99eca62f6c9e92fa..195df2a03047231e9a95325af57ebe9306825565 100644 (file)
@@ -444,17 +444,20 @@ defmodule Pleroma.UserTest do
     end
 
     setup do:
-            clear_config(:mrf_simple,
-              media_removal: [],
-              media_nsfw: [],
-              federated_timeline_removal: [],
-              report_removal: [],
-              reject: [],
-              followers_only: [],
-              accept: [],
-              avatar_removal: [],
-              banner_removal: [],
-              reject_deletes: []
+            clear_config(
+              [:mrf_simple],
+              %{
+                media_removal: [],
+                media_nsfw: [],
+                federated_timeline_removal: [],
+                report_removal: [],
+                reject: [],
+                followers_only: [],
+                accept: [],
+                avatar_removal: [],
+                banner_removal: [],
+                reject_deletes: []
+              }
             )
 
     setup do:
@@ -1324,7 +1327,7 @@ defmodule Pleroma.UserTest do
       collateral_user =
         insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
 
-      {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
+      {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
 
       refute User.blocks?(user, collateral_user)
     end
@@ -1342,7 +1345,7 @@ defmodule Pleroma.UserTest do
 
       user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
 
-      {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
+      {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
 
       assert User.blocks?(user, user_from_subdomain)
       assert User.blocks?(user, user_with_two_subdomains)
index 0569bfed309e8ed2cacbcc7d8950e91f2f528062..5f80c162967772881c7808ba76c489902f2a70a6 100644 (file)
@@ -46,8 +46,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
-      media_message = build_media_message()
+      clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Whatever reason"}])
+      media_message = build_media_message("sub.remote.instance")
       local_message = build_local_message()
 
       assert SimplePolicy.filter(media_message) ==
@@ -81,8 +81,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
-      media_message = build_media_message()
+      clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "yeah yeah"}])
+      media_message = build_media_message("sub.remote.instance")
       local_message = build_local_message()
 
       assert SimplePolicy.filter(media_message) ==
@@ -92,9 +92,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
   end
 
-  defp build_media_message do
+  defp build_media_message(domain \\ "remote.instance") do
     %{
-      "actor" => "https://remote.instance/users/bob",
+      "actor" => "https://#{domain}/users/bob",
       "type" => "Create",
       "object" => %{
         "attachment" => [%{}],
@@ -124,8 +124,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
-      report_message = build_report_message()
+      clear_config([:mrf_simple, :report_removal], [{"remote.instance", "suya"}])
+      report_message = build_report_message("sub.remote.instance")
       local_message = build_local_message()
 
       assert {:reject, _} = SimplePolicy.filter(report_message)
@@ -133,9 +133,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
   end
 
-  defp build_report_message do
+  defp build_report_message(domain \\ "remote.instance") do
     %{
-      "actor" => "https://remote.instance/users/bob",
+      "actor" => "https://#{domain}/users/bob",
       "type" => "Flag"
     }
   end
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
   describe "when :federated_timeline_removal" do
     test "is empty" do
       clear_config([:mrf_simple, :federated_timeline_removal], [])
-      {_, ftl_message} = build_ftl_actor_and_message()
+      {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob")
       local_message = build_local_message()
 
       assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
@@ -151,7 +151,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "has a matching host" do
-      {actor, ftl_message} = build_ftl_actor_and_message()
+      {actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob")
 
       ftl_message_actor_host =
         ftl_message
@@ -172,7 +172,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      {actor, ftl_message} = build_ftl_actor_and_message()
+      {actor, ftl_message} = build_ftl_actor_and_message("https://sub.remote.instance/users/bob")
 
       ftl_message_actor_host =
         ftl_message
@@ -181,7 +181,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
         |> Map.fetch!(:host)
 
       clear_config([:mrf_simple, :federated_timeline_removal], [
-        {"*." <> ftl_message_actor_host, "owo"}
+        {ftl_message_actor_host, "owo"}
       ])
 
       local_message = build_local_message()
@@ -196,7 +196,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "has a matching host but only as:Public in to" do
-      {_actor, ftl_message} = build_ftl_actor_and_message()
+      {_actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob")
 
       ftl_message_actor_host =
         ftl_message
@@ -253,8 +253,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
   end
 
-  defp build_ftl_actor_and_message do
-    actor = insert(:user)
+  defp build_ftl_actor_and_message(ap_id) do
+    actor = insert(:user, ap_id: ap_id)
 
     {actor,
      %{
@@ -282,9 +282,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "activity matches with wildcard domain" do
-      clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
+      clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
 
-      remote_message = build_remote_message()
+      remote_message = build_remote_message("sub.remote.instance")
 
       assert {:reject, _} = SimplePolicy.filter(remote_message)
     end
@@ -325,7 +325,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
   describe "when :followers_only" do
     test "is empty" do
       clear_config([:mrf_simple, :followers_only], [])
-      {_, ftl_message} = build_ftl_actor_and_message()
+      {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/alice")
       local_message = build_local_message()
 
       assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
@@ -412,10 +412,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "activity matches with wildcard domain" do
-      clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
+      clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
 
       local_message = build_local_message()
-      remote_message = build_remote_message()
+      remote_message = build_remote_message("sub.remote.instance")
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
       assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
@@ -457,9 +457,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
+      clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
 
-      remote_user = build_remote_user()
+      remote_user = build_remote_user("sub.remote.instance")
       {:ok, filtered} = SimplePolicy.filter(remote_user)
 
       refute filtered["icon"]
@@ -493,9 +493,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     end
 
     test "match with wildcard domain" do
-      clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
+      clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
 
-      remote_user = build_remote_user()
+      remote_user = build_remote_user("sub.remote.instance")
       {:ok, filtered} = SimplePolicy.filter(remote_user)
 
       refute filtered["image"]
@@ -553,10 +553,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
   end
 
   describe "when :reject_deletes match with wildcard domain" do
-    setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
+    setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
 
     test "it rejects the deletion" do
-      deletion_message = build_remote_deletion_message()
+      deletion_message = build_remote_deletion_message("sub.remote.instance")
 
       assert {:reject, _} = SimplePolicy.filter(deletion_message)
     end
@@ -570,13 +570,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     }
   end
 
-  defp build_remote_message do
-    %{"actor" => "https://remote.instance/users/bob"}
+  defp build_remote_message(domain \\ "remote.instance") do
+    %{"actor" => "https://#{domain}/users/bob"}
   end
 
-  defp build_remote_user do
+  defp build_remote_user(domain \\ "remote.instance") do
     %{
-      "id" => "https://remote.instance/users/bob",
+      "id" => "https://#{domain}/users/bob",
       "icon" => %{
         "url" => "http://example.com/image.jpg",
         "type" => "Image"
@@ -589,10 +589,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     }
   end
 
-  defp build_remote_deletion_message do
+  defp build_remote_deletion_message(domain \\ "remote.instance") do
     %{
       "type" => "Delete",
-      "actor" => "https://remote.instance/users/bob"
+      "actor" => "https://#{domain}/users/bob"
     }
   end
 end
index ed3233758b54160a8edc918ec2952de356523641..ec4dab30f0cdec500cc7e41509cb645132073bc8 100644 (file)
@@ -9,8 +9,8 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
 
   test "subdomains_regex/1" do
     assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [
-             ~r/^unsafe.tld$/i,
-             ~r/^(.*\.)*unsafe.tld$/i
+             ~r/^(.+\.)?unsafe\.tld$/i,
+             ~r/^(.+\.)?\*\.unsafe\.tld$/i
            ]
   end
 
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
     test "common domains" do
       regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"])
 
-      assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i]
+      assert regexes == [~r/^(.+\.)?unsafe\.tld$/i, ~r/^(.+\.)?unsafe2\.tld$/i]
 
       assert MRF.subdomain_match?(regexes, "unsafe.tld")
       assert MRF.subdomain_match?(regexes, "unsafe2.tld")
@@ -27,9 +27,9 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
     end
 
     test "wildcard domains with one subdomain" do
-      regexes = MRF.subdomains_regex(["*.unsafe.tld"])
+      regexes = MRF.subdomains_regex(["unsafe.tld"])
 
-      assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
+      assert regexes == [~r/^(.+\.)?unsafe\.tld$/i]
 
       assert MRF.subdomain_match?(regexes, "unsafe.tld")
       assert MRF.subdomain_match?(regexes, "sub.unsafe.tld")
@@ -38,9 +38,9 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
     end
 
     test "wildcard domains with two subdomains" do
-      regexes = MRF.subdomains_regex(["*.unsafe.tld"])
+      regexes = MRF.subdomains_regex(["unsafe.tld"])
 
-      assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
+      assert regexes == [~r/^(.+\.)?unsafe\.tld$/i]
 
       assert MRF.subdomain_match?(regexes, "unsafe.tld")
       assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld")
@@ -51,7 +51,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
     test "matches are case-insensitive" do
       regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"])
 
-      assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i]
+      assert regexes == [~r/^(.+\.)?UnSafe\.TLD$/i, ~r/^(.+\.)?UnSAFE2\.Tld$/i]
 
       assert MRF.subdomain_match?(regexes, "UNSAFE.TLD")
       assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD")