From cdf576b951459b34873a916394eb786452b0fb67 Mon Sep 17 00:00:00 2001 From: Oneric Date: Mon, 17 Mar 2025 22:21:19 +0100 Subject: [PATCH] federation/in: fix activity addressing of Pleroma unlisted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the object itself has the expected adressing for an "unlisted" post, we always use the Create activity’s adressing fields for permission checks. To avoid unintended effects on legacy objects we will continue to use the activity for access perm checks, but fix its addressing fields based on its object data. Ref: https://git.pleroma.social/pleroma/pleroma/-/issues/3323 --- .../web/activity_pub/transmogrifier.ex | 17 ++++++++++- .../transmogrifier/note_handling_test.exs | 28 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 9ed54fa6e..4469f3d49 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -118,7 +118,7 @@ defp normalise_addressing_public_list(%{} = map, [field | fields]) do Map.put(map, field, new_fval) else - map + Map.put(map, field, []) end normalise_addressing_public_list(map, fields) @@ -208,6 +208,20 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options) def fix_in_reply_to(object, _options), do: object + # Pleroma sends unlisted posts without addressing public scope in the enclosing activity + # but we only use the ativity for access perm cheks, see: + # https://git.pleroma.social/pleroma/pleroma/-/issues/3323 + defp fix_create_visibility(%{"type" => "Create", "object" => %{"cc" => occ}} = activity) do + acc = activity["cc"] + if Pleroma.Constants.as_public() in occ and not (Pleroma.Constants.as_public() in acc) do + Map.put(activity, "cc", [Pleroma.Constants.as_public() | acc]) + else + activity + end + end + + defp fix_create_visibility(activity), do: activity + def fix_quote_url(object, options \\ []) def fix_quote_url(%{"quoteUri" => quote_url} = object, options) @@ -513,6 +527,7 @@ defp handle_incoming_normalised( ) when objtype in ~w{Question Answer Audio Video Event Article Note Page} do fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1) + data = fix_create_visibility(data) object = data["object"] diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index 234a48990..e9271ce9a 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -17,6 +17,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do import Mock import Pleroma.Factory + require Pleroma.Constants + setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) :ok @@ -276,6 +278,32 @@ test "it ensures that address fields become lists" do refute is_nil(data["cc"]) end + test "it fixes Pleroma unlisted" do + # https://git.pleroma.social/pleroma/pleroma/-/issues/3323 + user1 = insert(:user) + user2 = insert(:user) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + |> Map.put("actor", user1.ap_id) + |> Map.put("cc", []) + |> Map.put("to", [user2.ap_id, user1.follower_address]) + + object = + data["object"] + |> Map.put("attributedTo", user1.ap_id) + |> Map.put("cc", [Pleroma.Constants.as_public()]) + |> Map.put("to", [user2.ap_id, user1.follower_address]) + |> Map.put("id", user1.ap_id <> "/activities/12345678") + + data = Map.put(data, "object", object) + + {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) + + assert "unlisted" == Pleroma.Web.ActivityPub.Visibility.get_visibility(activity) + end + test "it strips internal likes" do data = File.read!("test/fixtures/mastodon-post-activity.json")