Merge pull request 'Notifications: do not notify tagged users who cannot see the post' (#8022) from lambadalambda/pleroma:fix/mention-notify-access into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/8022
This commit is contained in:
lain 2026-10-27 12:38:20 +00:00
commit a4ce628a50
3 changed files with 143 additions and 1 deletions

View file

@ -0,0 +1 @@
Do not notify tagged users who cannot see the post

View file

@ -435,13 +435,56 @@ defmodule Pleroma.Web.CommonAPI.Utils do
%{} %{}
end end
tagged_mentions = maybe_extract_mentions(object_data) tagged_mentions =
maybe_extract_mentions(object_data)
|> filter_tags_to_qualified(activity)
recipients ++ tagged_mentions recipients ++ tagged_mentions
end end
def maybe_notify_mentioned_recipients(recipients, _), do: recipients def maybe_notify_mentioned_recipients(recipients, _), do: recipients
# Filter tagged mentions to ensure they can actually access the status
defp filter_tags_to_qualified(tagged_mentions, %Activity{
recipients: recipients,
data: data,
actor: actor
}) do
recipients =
if recipients && recipients != [],
do: recipients,
else:
(data["to"] || []) ++ (data["cc"] || []) ++ (data["bto"] || []) ++ (data["bcc"] || [])
cond do
recipients == [] ->
[]
Pleroma.Constants.as_public() in recipients ->
tagged_mentions
true ->
author = User.get_cached_by_ap_id(actor)
to_followers = match?(%User{}, author) and author.follower_address in recipients
Enum.filter(tagged_mentions, fn tagged ->
cond do
tagged in recipients ->
true
to_followers ->
case User.get_cached_by_ap_id(tagged) do
%User{} = tagged_user -> User.following?(tagged_user, author)
_ -> false
end
true ->
false
end
end)
end
end
def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = activity) do def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = activity) do
with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do
user user

View file

@ -7,6 +7,8 @@ defmodule Pleroma.NotificationTest do
import Pleroma.Factory import Pleroma.Factory
require Pleroma.Constants
alias Pleroma.FollowingRelationship alias Pleroma.FollowingRelationship
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
@ -628,6 +630,102 @@ defmodule Pleroma.NotificationTest do
assert other_user in enabled_receivers assert other_user in enabled_receivers
end 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 test "it does not send notifications to users who are only cc in new messages" do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)