Merge remote-tracking branch 'upstream/develop' into block-behavior
authorAlex Gleason <alex@alexgleason.me>
Wed, 14 Oct 2020 00:22:32 +0000 (19:22 -0500)
committerAlex Gleason <alex@alexgleason.me>
Wed, 14 Oct 2020 00:22:32 +0000 (19:22 -0500)
CHANGELOG.md
config/config.exs
config/description.exs
lib/pleroma/web/activity_pub/activity_pub.ex
test/pleroma/web/activity_pub/activity_pub_test.exs
test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs

index 8fc1750d181088c9476145faa312b42ae8d3c939..bb4c6d38382003f1eaf1b88b6b84a60021c099c6 100644 (file)
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
 - Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
 - Mix task option for force-unfollowing relays
+- `[:activitypub, :blockers_visible]` config to control visibility of blockers.
 
 ### Changed
 
@@ -48,6 +49,7 @@ switched to a new configuration mechanism, however it was not officially removed
 
 - Add documented-but-missing chat pagination.
 - Allow sending out emails again.
+- See your own post when addressing a user from a blocked domain.
 
 ## Unreleased (Patch)
 
index 273da5bb6728faf2daf12f5bee3e66c01347d12b..0853a5946f9749d5231242f08e74a84e63d1d24e 100644 (file)
@@ -363,6 +363,7 @@ config :pleroma, :manifest,
 config :pleroma, :activitypub,
   unfollow_blocked: true,
   outgoing_blocks: true,
+  blockers_visible: true,
   follow_handshake_timeout: 500,
   note_replies_output_limit: 5,
   sign_object_fetches: true,
index 6e83a8e094571e8699a857191532c5991d51c9a6..6bed8a8d245fb76c7219bc88af2692eb7401f834 100644 (file)
@@ -2092,6 +2092,11 @@ config :pleroma, :config_description, [
         type: :boolean,
         description: "Whether to federate blocks to other instances"
       },
+      %{
+        key: :blockers_visible,
+        type: :boolean,
+        description: "Whether a user can see someone who has blocked them"
+      },
       %{
         key: :sign_object_fetches,
         type: :boolean,
index eb44cffec14eddb5634a3973a1f6625fbcd14acb..c9712d245ac7a0bbefa5c1ea4483aeff0d3836fc 100644 (file)
@@ -410,6 +410,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> maybe_preload_bookmarks(opts)
     |> maybe_set_thread_muted_field(opts)
     |> restrict_blocked(opts)
+    |> restrict_blockers_visibility(opts)
     |> restrict_recipients(recipients, opts[:user])
     |> restrict_filtered(opts)
     |> where(
@@ -791,10 +792,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       where:
         fragment(
           """
-          ?->>'type' != 'Create'     -- This isn't a Create      
+          ?->>'type' != 'Create'     -- This isn't a Create
           OR ?->>'inReplyTo' is null -- this isn't a reply
-          OR ? && array_remove(?, ?) -- The recipient is us or one of our friends, 
-                                     -- unless they are the author (because authors 
+          OR ? && array_remove(?, ?) -- The recipient is us or one of our friends,
+                                     -- unless they are the author (because authors
                                      -- are also part of the recipients). This leads
                                      -- to a bug that self-replies by friends won't
                                      -- show up.
@@ -850,7 +851,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
     from(
       [activity, object: o] in query,
+      # You don't block the author
       where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
+
+      # You don't block any recipients, and didn't author the post
       where:
         fragment(
           "((not (? && ?)) or ? = ?)",
@@ -859,12 +863,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           activity.actor,
           ^user.ap_id
         ),
+
+      # You don't block the domain of any recipients, and didn't author the post
       where:
         fragment(
-          "recipients_contain_blocked_domains(?, ?) = false",
+          "(recipients_contain_blocked_domains(?, ?) = false) or ? = ?",
           activity.recipients,
-          ^domain_blocks
+          ^domain_blocks,
+          activity.actor,
+          ^user.ap_id
         ),
+
+      # It's not a boost of a user you block
       where:
         fragment(
           "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
@@ -872,6 +882,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           activity.data,
           ^blocked_ap_ids
         ),
+
+      # You don't block the author's domain, and also don't follow the author
       where:
         fragment(
           "(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)",
@@ -880,6 +892,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           activity.actor,
           ^following_ap_ids
         ),
+
+      # Same as above, but checks the Object
       where:
         fragment(
           "(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)",
@@ -893,6 +907,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp restrict_blocked(query, _), do: query
 
+  defp restrict_blockers_visibility(query, %{blocking_user: %User{} = user}) do
+    if Config.get([:activitypub, :blockers_visible]) == true do
+      query
+    else
+      blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block])
+
+      from(
+        activity in query,
+        # The author doesn't block you
+        where: fragment("not (? = ANY(?))", activity.actor, ^blocker_ap_ids),
+
+        # It's not a boost of a user that blocks you
+        where:
+          fragment(
+            "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
+            activity.data,
+            activity.data,
+            ^blocker_ap_ids
+          )
+      )
+    end
+  end
+
+  defp restrict_blockers_visibility(query, _), do: query
+
   defp restrict_unlisted(query, %{restrict_unlisted: true}) do
     from(
       activity in query,
@@ -1093,6 +1132,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_state(opts)
     |> restrict_favorited_by(opts)
     |> restrict_blocked(restrict_blocked_opts)
+    |> restrict_blockers_visibility(opts)
     |> restrict_muted(restrict_muted_opts)
     |> restrict_filtered(opts)
     |> restrict_media(opts)
index 804305a1381321e35c4ae38dcc8d67febcecf5de..e4661b4788569a5f1465e552fcdf4d9d438390e8 100644 (file)
@@ -622,6 +622,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     assert Enum.member?(activities, activity_one)
   end
 
+  test "always see your own posts even when they address people you block" do
+    user = insert(:user)
+    blockee = insert(:user)
+
+    {:ok, _} = User.block(user, blockee)
+    {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{blockee.nickname}"})
+
+    activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+    assert Enum.member?(activities, activity)
+  end
+
   test "doesn't return transitive interactions concerning blocked users" do
     blocker = insert(:user)
     blockee = insert(:user)
@@ -721,6 +733,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     refute repeat_activity in activities
   end
 
+  test "see your own posts even when they adress actors from blocked domains" do
+    user = insert(:user)
+
+    domain = "dogwhistle.zone"
+    domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
+
+    {:ok, user} = User.block_domain(user, domain)
+
+    {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{domain_user.nickname}"})
+
+    activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+    assert Enum.member?(activities, activity)
+  end
+
   test "does return activities from followed users on blocked domains" do
     domain = "meanies.social"
     domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
index c6e0268fdbdaa80fd885a93976d27f704a98260e..e2a83081163da8ff47eec8878364ed05c9873394 100644 (file)
@@ -126,6 +126,24 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
       [%{"id" => ^reply_from_me}, %{"id" => ^activity_id}] = response
     end
 
+    test "doesn't return posts from users who blocked you when :blockers_visible is disabled" do
+      clear_config([:activitypub, :blockers_visible], false)
+
+      %{conn: conn, user: blockee} = oauth_access(["read:statuses"])
+      blocker = insert(:user)
+      {:ok, _} = User.block(blocker, blockee)
+
+      conn = assign(conn, :user, blockee)
+
+      {:ok, _} = CommonAPI.post(blocker, %{status: "hey!"})
+
+      response =
+        get(conn, "/api/v1/timelines/public")
+        |> json_response_and_validate_schema(200)
+
+      assert length(response) == 0
+    end
+
     test "doesn't return replies if follow is posting with users from blocked domain" do
       %{conn: conn, user: blocker} = oauth_access(["read:statuses"])
       friend = insert(:user)