From d2364276a1cbfb2b6b3851fd9fb0e48d773b923b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 10 Oct 2020 01:21:57 -0500 Subject: [PATCH 1/7] Blocks: always see your own posts --- lib/pleroma/web/activity_pub/activity_pub.ex | 23 +++++++++++++---- test/web/activity_pub/activity_pub_test.exs | 27 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index eb44cffec..bf89c228a 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -791,10 +791,10 @@ defp restrict_replies(query, %{ 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 +850,10 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) 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 +862,18 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) 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 +881,8 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) 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 +891,8 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do activity.actor, ^following_ap_ids ), + + # Same as above, but checks the Object where: fragment( "(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)", diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 804305a13..e4661b478 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -622,6 +622,18 @@ test "doesn't return blocked activities" 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 @@ test "doesn't return activities from blocked domains" 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"}) From 2fc7ce3e1e2fb746305944d40ac74da16d48f7aa Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 10 Oct 2020 01:29:41 -0500 Subject: [PATCH 2/7] Blocks: add blockers_visible config --- config/config.exs | 1 + config/description.exs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/config/config.exs b/config/config.exs index d53663d36..befc6840d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -363,6 +363,7 @@ 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, diff --git a/config/description.exs b/config/description.exs index 3902b9632..4f495e828 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2092,6 +2092,11 @@ 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, From 7c2d0e378c45dd1c03fbd4a9d338bbeb4f9d2610 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 10 Oct 2020 03:41:35 -0500 Subject: [PATCH 3/7] Blocks: make blockers_visible config work --- lib/pleroma/web/activity_pub/activity_pub.ex | 27 +++++++++++++++++++ .../controllers/timeline_controller_test.exs | 18 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index bf89c228a..c9712d245 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -410,6 +410,7 @@ def fetch_activities_for_context_query(context, opts) 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( @@ -906,6 +907,31 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) 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, @@ -1106,6 +1132,7 @@ def fetch_activities_query(recipients, opts \\ %{}) 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) diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs index c6e0268fd..e2a830811 100644 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -126,6 +126,24 @@ test "doesn't return replies if follower is posting with blocked user" 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) From 5c8d2c468c3a14cde029e7aeedd0cdb580cce1df Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 10 Oct 2020 03:44:20 -0500 Subject: [PATCH 4/7] Blocks: update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc1750d1..bb4c6d383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) From 2aeb229de3f59e1704c633c31415e7e834f6ba67 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 4 Nov 2020 16:23:24 +0100 Subject: [PATCH 5/7] Cheatsheet: Add info about :blockers_visible --- docs/configuration/cheatsheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index ebf95ebc9..75cb4b348 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -205,6 +205,7 @@ config :pleroma, :mrf_user_allowlist, %{ ### :activitypub * `unfollow_blocked`: Whether blocks result in people getting unfollowed * `outgoing_blocks`: Whether to federate blocks to other instances +* `blockers_visible`: Whether a user can see the posts of users who blocked them * `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question * `sign_object_fetches`: Sign object fetches with HTTP signatures * `authorized_fetch_mode`: Require HTTP signatures for AP fetches From cc09079aea54f5ff754925e0d5fbbc3b268dcb6d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 6 Jan 2021 15:39:14 -0600 Subject: [PATCH 6/7] Exclude blockers from notifications when `blockers_visible: false` --- lib/pleroma/notification.ex | 12 ++++++++++++ .../notification_controller_test.exs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index dd7a1c824..e9c9b3ea2 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -132,6 +132,7 @@ def for_user_query(user, opts \\ %{}) do |> preload([n, a, o], activity: {a, object: o}) |> exclude_notification_muted(user, exclude_notification_muted_opts) |> exclude_blocked(user, exclude_blocked_opts) + |> exclude_blockers(user) |> exclude_filtered(user) |> exclude_visibility(opts) end @@ -145,6 +146,17 @@ defp exclude_blocked(query, user, opts) do |> FollowingRelationship.keep_following_or_not_domain_blocked(user) end + defp exclude_blockers(query, user) do + if Pleroma.Config.get([:activitypub, :blockers_visible]) == true do + query + else + blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block]) + + query + |> where([n, a], a.actor not in ^blocker_ap_ids) + end + end + defp exclude_notification_muted(query, _, %{@include_muted_option => true}) do query end diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 9ac8488f6..ef35bdd00 100644 --- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -103,6 +103,25 @@ test "by default, does not contain pleroma:report" do assert [_] = result end + test "excludes mentions from blockers when blockers_visible is false" do + clear_config([:activitypub, :blockers_visible], false) + + %{user: user, conn: conn} = oauth_access(["read:notifications"]) + blocker = insert(:user) + + {:ok, _} = CommonAPI.block(blocker, user) + {:ok, activity} = CommonAPI.post(blocker, %{status: "hi @#{user.nickname}"}) + + {:ok, [_notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/notifications") + + assert [] == json_response_and_validate_schema(conn, 200) + end + test "getting a single notification" do %{user: user, conn: conn} = oauth_access(["read:notifications"]) other_user = insert(:user) From b7b05a074867c1444dd539d6d2331f6d5504f6e6 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 6 Jan 2021 15:42:36 -0600 Subject: [PATCH 7/7] Oopsie whoopsie fix changelog --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10968d02b..dc1b4b6c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,13 +141,7 @@ switched to a new configuration mechanism, however it was not officially removed - Allow sending out emails again. - Allow sending chat messages to yourself - OStatus / static FE endpoints: fixed inaccessibility for anonymous users on non-federating instances, switched to handling per `:restrict_unauthenticated` setting. -<<<<<<< HEAD -- Mastodon API: Current user is now included in conversation if it's the only participant -- Mastodon API: Fixed last_status.account being not filled with account data -- See your own post when addressing a user from a blocked domain. -======= - Fix remote users with a whitespace name. ->>>>>>> upstream/develop ### Upgrade notes