Also use actor_type to determine if an account is a bot in antiFollowbotPolicy
authorIlja <pleroma@spectraltheorem.be>
Sun, 8 May 2022 18:10:40 +0000 (18:10 +0000)
committerFloatingGhost <hannah@coffee-and-dreams.uk>
Wed, 29 Jun 2022 19:47:44 +0000 (20:47 +0100)
CHANGELOG.md
docs/configuration/cheatsheet.md
lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs

index 1cc902d583af299ad505e66d06e92f14df83e8df..2119c8e21633f392b97659bc1fe651773046956f 100644 (file)
@@ -117,6 +117,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Improved Twittercard and OpenGraph meta tag generation including thumbnails and image dimension metadata when available.
 - AdminAPI: sort users so the newest are at the top.
 - ActivityPub Client-to-Server(C2S): Limitation on the type of Activity/Object are lifted as they are now passed through ObjectValidators
+- MRF (`AntiFollowbotPolicy`): Bot accounts are now also considered followbots. Users can still allow bots to follow them by first following the bot.
 
 ### Added
 
index 3b8f8cc52f6d4445b67c065a688b52263a3ea881..50281f4516f7df1b7e24a669ee7bde90a44f42c2 100644 (file)
@@ -125,6 +125,8 @@ To add configuration to your config file, you can copy it from the base config.
     * `Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy`: Sets a default expiration on all posts made by users of the local instance. Requires `Pleroma.Workers.PurgeExpiredActivity` to be enabled for processing the scheduled delections.
     * `Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy`: Makes all bot posts to disappear from public timelines.
     * `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed.
+    * `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot.
+    * `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.
 
index 851e95d226e7f5b216c500e46a194e5333f621e1..627f52168d469429185ec1067fd662a8c2cc02e3 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
   defp score_displayname("fedibot"), do: 1.0
   defp score_displayname(_), do: 0.0
 
-  defp determine_if_followbot(%User{nickname: nickname, name: displayname}) do
+  defp determine_if_followbot(%User{nickname: nickname, name: displayname, actor_type: actor_type}) do
     # nickname will be a binary string except when following a relay
     nick_score =
       if is_binary(nickname) do
@@ -45,19 +45,32 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
         0.0
       end
 
-    nick_score + name_score
+    # actor_type "Service" is a Bot account
+    actor_type_score =
+      if actor_type == "Service" do
+        1.0
+      else
+        0.0
+      end
+
+    nick_score + name_score + actor_type_score
   end
 
   defp determine_if_followbot(_), do: 0.0
 
+  defp bot_allowed?(%{"object" => target}, bot_actor) do
+    %User{} = user = normalize_by_ap_id(target)
+
+    User.following?(user, bot_actor)
+  end
+
   @impl true
   def filter(%{"type" => "Follow", "actor" => actor_id} = message) do
     %User{} = actor = normalize_by_ap_id(actor_id)
 
     score = determine_if_followbot(actor)
 
-    # TODO: scan biography data for keywords and score it somehow.
-    if score < 0.8 do
+    if score < 0.8 || bot_allowed?(message, actor) do
       {:ok, message}
     else
       {:reject, "[AntiFollowbotPolicy] Scored #{actor_id} as #{score}"}
index d5af3a9b652d1c93481d1f7f5fd2e9929b3a48ef..14a6ae52b1eefee345cb88e1bebd7eefccb42e06 100644 (file)
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
   use Pleroma.DataCase, async: true
   import Pleroma.Factory
 
+  alias Pleroma.User
   alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy
 
   describe "blocking based on attributes" do
@@ -38,21 +39,55 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
 
       assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
     end
+
+    test "matches followbots by actor_type" do
+      actor = insert(:user, %{actor_type: "Service"})
+      target = insert(:user)
+
+      message = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "type" => "Follow",
+        "actor" => actor.ap_id,
+        "object" => target.ap_id,
+        "id" => "https://example.com/activities/1234"
+      }
+
+      assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
+    end
   end
 
-  test "it allows non-followbots" do
-    actor = insert(:user)
-    target = insert(:user)
+  describe "it allows" do
+    test "non-followbots" do
+      actor = insert(:user)
+      target = insert(:user)
 
-    message = %{
-      "@context" => "https://www.w3.org/ns/activitystreams",
-      "type" => "Follow",
-      "actor" => actor.ap_id,
-      "object" => target.ap_id,
-      "id" => "https://example.com/activities/1234"
-    }
+      message = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "type" => "Follow",
+        "actor" => actor.ap_id,
+        "object" => target.ap_id,
+        "id" => "https://example.com/activities/1234"
+      }
 
-    {:ok, _} = AntiFollowbotPolicy.filter(message)
+      {:ok, _} = AntiFollowbotPolicy.filter(message)
+    end
+
+    test "bots if the target follows the bots" do
+      actor = insert(:user, %{actor_type: "Service"})
+      target = insert(:user)
+
+      User.follow(target, actor)
+
+      message = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "type" => "Follow",
+        "actor" => actor.ap_id,
+        "object" => target.ap_id,
+        "id" => "https://example.com/activities/1234"
+      }
+
+      {:ok, _} = AntiFollowbotPolicy.filter(message)
+    end
   end
 
   test "it gracefully handles nil display names" do