diff options
| -rw-r--r-- | CHANGELOG.md | 7 | ||||
| -rw-r--r-- | config/config.exs | 1 | ||||
| -rw-r--r-- | config/description.exs | 5 | ||||
| -rw-r--r-- | docs/configuration/cheatsheet.md | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 44 | ||||
| -rw-r--r-- | test/pleroma/web/activity_pub/activity_pub_test.exs | 27 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs | 18 | 
7 files changed, 101 insertions, 2 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index b70302bbf..10968d02b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Support pagination of blocks and mutes.  - Account backup.  - Configuration: Add `:instance, autofollowing_nicknames` setting to provide a way to make accounts automatically follow new users that register on the local Pleroma instance. +- `[:activitypub, :blockers_visible]` config to control visibility of blockers.  - Ability to view remote timelines, with ex. `/api/v1/timelines/public?instance=lain.com` and streams `public:remote` and `public:remote:media`.  - The site title is now injected as a `title` tag like preloads or metadata.  - Password reset tokens now are not accepted after a certain age. @@ -140,7 +141,13 @@ 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 diff --git a/config/config.exs b/config/config.exs index d6d116314..569d7ad0a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -352,6 +352,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, diff --git a/config/description.exs b/config/description.exs index f438a88ab..04485bcfd 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1693,6 +1693,11 @@ config :pleroma, :config_description, [          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,          description: "Sign object fetches with HTTP signatures" diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 85551362c..07dc04fcd 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -206,6 +206,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 diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8c2610eeb..0923e19e4 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -429,6 +429,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( @@ -878,7 +879,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 ? = ?)", @@ -887,12 +891,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' \\?| ?)", @@ -900,6 +910,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(?)", @@ -908,6 +920,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(?)", @@ -921,6 +935,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, @@ -1116,6 +1155,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) diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 9eb7ae86b..3027d4370 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -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"}) diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index 655e35ac6..d69eaf9b1 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -161,6 +161,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) | 
