commit: 774e0cb17218c764791df522d6b6f7d9d2facfd5
parent f38e9228ef01ee575224faef72c820525dd73c22
Author: feld <feld@feld.me>
Date: Fri, 13 Jun 2025 06:27:04 +0000
Merge branch 'unlisted-fix' into 'develop'
Public getting stripped from unlisted activity CC
See merge request pleroma/pleroma!4353
Diffstat:
3 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/changelog.d/preserve-public-cc.fix b/changelog.d/preserve-public-cc.fix
@@ -0,0 +1 @@
+Fix federation issue where Public visibility information in cc field was lost when sent to remote servers, causing posts to appear with inconsistent visibility across instances
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
@@ -93,7 +93,20 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
- cc = Map.get(params, :cc, [])
+ param_cc = Map.get(params, :cc, [])
+
+ original_cc = Map.get(data, "cc", [])
+
+ public_address = Pleroma.Constants.as_public()
+
+ # Ensure unlisted posts don't lose the public address in the cc
+ # if the param_cc was set
+ cc =
+ if public_address in original_cc and public_address not in param_cc do
+ [public_address | param_cc]
+ else
+ param_cc
+ end
json =
data
diff --git a/test/pleroma/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs
@@ -520,4 +520,105 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
assert decoded["cc"] == []
end
+
+ test "unlisted activities retain public address in cc" do
+ user = insert(:user)
+
+ # simulate unlistd activity by only having
+ # public address in cc
+ activity =
+ insert(:note_activity,
+ user: user,
+ data_attrs: %{
+ "cc" => [@as_public],
+ "to" => [user.follower_address]
+ }
+ )
+
+ assert @as_public in activity.data["cc"]
+
+ prepared =
+ Publisher.prepare_one(%{
+ inbox: "https://remote.instance/users/someone/inbox",
+ activity_id: activity.id
+ })
+
+ {:ok, decoded} = Jason.decode(prepared.json)
+
+ assert @as_public in decoded["cc"]
+
+ # maybe we also have another inbox in cc
+ # during Publishing
+ activity =
+ insert(:note_activity,
+ user: user,
+ data_attrs: %{
+ "cc" => [@as_public],
+ "to" => [user.follower_address]
+ }
+ )
+
+ prepared =
+ Publisher.prepare_one(%{
+ inbox: "https://remote.instance/users/someone/inbox",
+ activity_id: activity.id,
+ cc: ["https://remote.instance/users/someone_else/inbox"]
+ })
+
+ {:ok, decoded} = Jason.decode(prepared.json)
+
+ assert decoded["cc"] == [@as_public, "https://remote.instance/users/someone_else/inbox"]
+ end
+
+ test "public address in cc parameter is preserved" do
+ user = insert(:user)
+
+ cc_with_public = [@as_public, "https://example.org/users/other"]
+
+ activity =
+ insert(:note_activity,
+ user: user,
+ data_attrs: %{
+ "cc" => cc_with_public,
+ "to" => [user.follower_address]
+ }
+ )
+
+ assert @as_public in activity.data["cc"]
+
+ prepared =
+ Publisher.prepare_one(%{
+ inbox: "https://remote.instance/users/someone/inbox",
+ activity_id: activity.id,
+ cc: cc_with_public
+ })
+
+ {:ok, decoded} = Jason.decode(prepared.json)
+
+ assert cc_with_public == decoded["cc"]
+ end
+
+ test "cc parameter is preserved" do
+ user = insert(:user)
+
+ activity =
+ insert(:note_activity,
+ user: user,
+ data_attrs: %{
+ "cc" => ["https://example.com/specific/user"],
+ "to" => [user.follower_address]
+ }
+ )
+
+ prepared =
+ Publisher.prepare_one(%{
+ inbox: "https://remote.instance/users/someone/inbox",
+ activity_id: activity.id,
+ cc: ["https://example.com/specific/user"]
+ })
+
+ {:ok, decoded} = Jason.decode(prepared.json)
+
+ assert decoded["cc"] == ["https://example.com/specific/user"]
+ end
end