diff --git a/changelog.d/mention-notify-access.security b/changelog.d/mention-notify-access.security new file mode 100644 index 000000000..2f1830079 --- /dev/null +++ b/changelog.d/mention-notify-access.security @@ -0,0 +1 @@ +Do not notify tagged users who cannot see the post diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 64958e1f2..b66e0ace6 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -465,7 +465,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do true -> author = User.get_cached_by_ap_id(actor) - to_followers = author.follower_address in recipients + to_followers = match?(%User{}, author) and author.follower_address in recipients Enum.filter(tagged_mentions, fn tagged -> cond do @@ -473,8 +473,10 @@ defmodule Pleroma.Web.CommonAPI.Utils do true to_followers -> - tagged_user = User.get_cached_by_ap_id(tagged) - User.following?(tagged_user, author) + case User.get_cached_by_ap_id(tagged) do + %User{} = tagged_user -> User.following?(tagged_user, author) + _ -> false + end true -> false diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 992b15f8b..694af27aa 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.NotificationTest do import Pleroma.Factory + require Pleroma.Constants + alias Pleroma.FollowingRelationship alias Pleroma.Notification alias Pleroma.Repo @@ -611,6 +613,102 @@ defmodule Pleroma.NotificationTest do assert other_user in enabled_receivers end + defp incoming_note_tagging(author, to, tagged_ap_ids) do + tags = Enum.map(tagged_ap_ids, &%{"type" => "Mention", "href" => &1, "name" => &1}) + + {:ok, activity} = + Transmogrifier.handle_incoming(%{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Create", + "to" => to, + "actor" => author.ap_id, + "object" => %{ + "type" => "Note", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "to" => to, + "content" => "tagged", + "tag" => tags, + "attributedTo" => author.ap_id + } + }) + + activity + end + + defp notified_ap_ids(activity), + do: activity |> Notification.get_notified_from_activity() |> Enum.map(& &1.ap_id) + + test "it does not notify tagged users who cannot see a followers-only post" do + author = insert(:user) + tagged = insert(:user) + + activity = incoming_note_tagging(author, [author.follower_address], [tagged.ap_id]) + + refute tagged.ap_id in notified_ap_ids(activity) + end + + test "it notifies tagged followers of a followers-only post" do + author = insert(:user) + tagged = insert(:user) + {:ok, _, _} = Pleroma.User.follow(tagged, author) + + activity = incoming_note_tagging(author, [author.follower_address], [tagged.ap_id]) + + assert tagged.ap_id in notified_ap_ids(activity) + end + + test "it does not notify tagged users who are not addressed by a direct message" do + author = insert(:user) + addressed = insert(:user) + tagged = insert(:user) + + activity = incoming_note_tagging(author, [addressed.ap_id], [tagged.ap_id]) + receivers = notified_ap_ids(activity) + + assert addressed.ap_id in receivers + refute tagged.ap_id in receivers + end + + test "it notifies tagged users of a public post even if they are not addressed" do + author = insert(:user) + tagged = insert(:user) + + activity = + incoming_note_tagging(author, [Pleroma.Constants.as_public()], [tagged.ap_id]) + + assert tagged.ap_id in notified_ap_ids(activity) + end + + test "it does not notify tagged users with a pending follow request" do + author = insert(:user, is_locked: true) + tagged = insert(:user) + {:ok, _, _, _} = CommonAPI.follow(author, tagged) + + activity = incoming_note_tagging(author, [author.follower_address], [tagged.ap_id]) + + refute tagged.ap_id in notified_ap_ids(activity) + end + + test "it ignores tags of unknown users in a followers-only post" do + author = insert(:user) + tagged = insert(:user) + + follower = insert(:user) + {:ok, _, _} = Pleroma.User.follow(follower, author) + + activity = + incoming_note_tagging(author, [author.follower_address], [ + "https://unknown.example/users/nobody", + tagged.ap_id, + follower.ap_id + ]) + + receivers = notified_ap_ids(activity) + + refute tagged.ap_id in receivers + assert follower.ap_id in receivers + end + test "it does not send notifications to users who are only cc in new messages" do user = insert(:user) other_user = insert(:user)