Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/changelog.d/quiet-reply.fix b/changelog.d/quiet-reply.fix
new file mode 100644
index 000000000..301a6fae8
--- /dev/null
+++ b/changelog.d/quiet-reply.fix
@@ -0,0 +1 @@
+Addressing of Unlisted posts rewritten by MRF Quiet Reply did not make the post viewable to non-followers.
diff --git a/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex b/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
index b07dc3b56..405fcf240 100644
--- a/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
+++ b/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
@@ -1,60 +1,63 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.QuietReply do
@moduledoc """
QuietReply alters the scope of activities from local users when replying by enforcing them to be "Unlisted" or "Quiet Public". This delivers the activity to all the expected recipients and instances, but it will not be published in the Federated / The Whole Known Network timelines. It will still be published to the Home timelines of the user's followers and visible to anyone who opens the thread.
"""
require Pleroma.Constants
alias Pleroma.User
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def history_awareness, do: :auto
@impl true
def filter(
%{
"type" => "Create",
- "to" => to,
- "cc" => cc,
+ "to" => _activity_to,
+ "cc" => _activity_cc,
"object" => %{
"actor" => actor,
"type" => "Note",
- "inReplyTo" => in_reply_to
+ "inReplyTo" => in_reply_to,
+ "to" => to,
+ "cc" => cc
}
} = activity
) do
with true <- is_binary(in_reply_to),
false <- match?([], cc),
%User{follower_address: followers_collection, local: true} <-
User.get_by_ap_id(actor) do
- updated_to =
+ updated_object_to =
to
|> Kernel.++([followers_collection])
|> Kernel.--([Pleroma.Constants.as_public()])
+ |> Enum.uniq()
updated_cc = [Pleroma.Constants.as_public()]
updated_activity =
activity
- |> Map.put("to", updated_to)
+ |> Map.put("to", [])
|> Map.put("cc", updated_cc)
- |> put_in(["object", "to"], updated_to)
+ |> put_in(["object", "to"], updated_object_to)
|> put_in(["object", "cc"], updated_cc)
{:ok, updated_activity}
else
_ -> {:ok, activity}
end
end
@impl true
def filter(activity), do: {:ok, activity}
@impl true
def describe, do: {:ok, %{}}
end
diff --git a/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs b/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
index 79e64d650..a35d5f338 100644
--- a/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
@@ -1,140 +1,142 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.QuietReplyTest do
use Pleroma.DataCase
import Pleroma.Factory
require Pleroma.Constants
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.MRF.QuietReply
alias Pleroma.Web.CommonAPI
test "replying to public post is forced to be quiet" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [
batman.ap_id,
Pleroma.Constants.as_public()
],
"cc" => [robin.follower_address],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman Wait up, I forgot my spandex!",
"to" => [
batman.ap_id,
Pleroma.Constants.as_public()
],
"cc" => [robin.follower_address],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
- expected_to = [batman.ap_id, robin.follower_address]
- expected_cc = [Pleroma.Constants.as_public()]
+ expected_activity_to = []
+ expected_activity_cc = [Pleroma.Constants.as_public()]
+ expected_object_to = [batman.ap_id, robin.follower_address]
+ expected_object_cc = [Pleroma.Constants.as_public()]
assert {:ok, filtered} = QuietReply.filter(reply)
- assert expected_to == filtered["to"]
- assert expected_cc == filtered["cc"]
- assert expected_to == filtered["object"]["to"]
- assert expected_cc == filtered["object"]["cc"]
+ assert expected_activity_to == filtered["to"]
+ assert expected_activity_cc == filtered["cc"]
+ assert expected_object_to == filtered["object"]["to"]
+ assert expected_object_cc == filtered["object"]["cc"]
end
test "replying to unlisted post is unmodified" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!", visibility: "private"})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [batman.ap_id],
"cc" => [],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman Wait up, I forgot my spandex!",
"to" => [batman.ap_id],
"cc" => [],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
assert {:ok, filtered} = QuietReply.filter(reply)
assert match?(^filtered, reply)
end
test "replying direct is unmodified" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [batman.ap_id],
"cc" => [],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman Wait up, I forgot my spandex!",
"to" => [batman.ap_id],
"cc" => [],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
assert {:ok, filtered} = QuietReply.filter(reply)
assert match?(^filtered, reply)
end
test "replying followers-only is unmodified" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman Wait up, I forgot my spandex!",
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
assert {:ok, filtered} = QuietReply.filter(reply)
assert match?(^filtered, reply)
end
test "non-reply posts are unmodified" do
batman = insert(:user, nickname: "batman")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
assert {:ok, filtered} = QuietReply.filter(post)
assert match?(^filtered, post)
end
end

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 30, 1:36 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1799128
Default Alt Text
(7 KB)

Event Timeline