diff --git a/changelog.d/transmogrifier-aspublic.fix b/changelog.d/transmogrifier-aspublic.fix new file mode 100644 index 000000000..36610cbed --- /dev/null +++ b/changelog.d/transmogrifier-aspublic.fix @@ -0,0 +1 @@ +Transmogrifier: convert "as:Public" to full w3 URL diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index f0f3fef90..2e0f7a8a0 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -20,7 +20,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do require Pleroma.Constants def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do - {:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback) + # Fix as:Public/Public before ObjectID casting drops it, but keep `field_fallback` + # semantics (only used when the field is missing). + recipients = + %{field => message[field] || field_fallback} + |> Transmogrifier.fix_addressing_list(field) + |> Transmogrifier.fix_addressing_public(field) + |> Map.fetch!(field) + + {:ok, data} = ObjectValidators.Recipients.cast(recipients) data = Enum.reject(data, fn x -> diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 00339fad9..a358f3925 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -104,6 +104,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + @doc """ + Bovine compatibility + https://codeberg.org/bovine/bovine/issues/53 + """ + def fix_addressing_public(map, field) do + addrs = Map.get(map, field, []) |> List.wrap() + + Map.put( + map, + field, + Enum.map(addrs, fn + "Public" -> Pleroma.Constants.as_public() + "as:Public" -> Pleroma.Constants.as_public() + x -> x + end) + ) + end + # if directMessage flag is set to true, leave the addressing alone def fix_explicit_addressing(%{"directMessage" => true} = object, _follower_collection), do: object @@ -161,6 +179,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_addressing_list("cc") |> fix_addressing_list("bto") |> fix_addressing_list("bcc") + |> fix_addressing_public("to") + |> fix_addressing_public("cc") + |> fix_addressing_public("bto") + |> fix_addressing_public("bcc") |> fix_explicit_addressing(follower_collection) |> fix_implicit_addressing(follower_collection) end diff --git a/test/fixtures/bovine-bogus-public-note.json b/test/fixtures/bovine-bogus-public-note.json new file mode 100644 index 000000000..032bf49dc --- /dev/null +++ b/test/fixtures/bovine-bogus-public-note.json @@ -0,0 +1,34 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + "https://www.w3.org/ns/did/v1", + "https://w3id.org/security/multikey/v1", + { + "Hashtag": "as:Hashtag" + } + ], + "attributedTo": "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0", + "cc": [ + "https://mymath.rocks/endpoints/30zoCe7haKBEFolH4rbAmKj-t9_bG0c2X2kMQkJk5qY", + "https://mastodon.social/users/nikclayton" + ], + "content": "
\n\nI note that mymath.rocks does not provide this information.
\n
I'm a big believer in "Do as I say, not as I did".
\nI could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.
\nI think the above statement also addresses a main failure of the Fediverse. People, e.g. me, would love to fix stuff. Unfortunately, we lack the focus to address a lot of issues, e.g. nodeinfo sucks. So stuff gets done in a broken way.
\nI think the main challenge the Fediverse has faced, and failed at, is avoiding the above situation. To continue the example, there is no way for somebody to say: Let's fix nodeinfo and people will follow their ideas.
\n", + "id": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026", + "inReplyTo": "https://mastodon.social/users/nikclayton/statuses/115496665258618127", + "likes": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/likes", + "published": "2025-11-06T08:21:17.790Z", + "replies": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/replies", + "shares": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/shares", + "source": { + "content": "> I note that mymath.rocks does not provide this information.\n\nI'm a big believer in \"Do as I say, not as I __did__\".\n\nI could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.\n\nI think the above statement also addresses a main failure of the Fediverse. People, e.g. me, would love to fix stuff. Unfortunately, we lack the focus to address a lot of issues, e.g. nodeinfo sucks. So stuff gets done in a broken way.\n\nI think the main challenge the Fediverse has faced, and failed at, is avoiding the above situation. To continue the example, there is no way for somebody to say: Let's fix nodeinfo and people will follow their ideas.", + "mediaType": "text/markdown" + }, + "tag": { + "href": "https://mastodon.social/users/nikclayton", + "name": "https://mastodon.social/users/nikclayton", + "type": "Mention" + }, + "to": "as:Public", + "type": "Note" +} diff --git a/test/pleroma/web/activity_pub/object_validators/create_generic_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/create_generic_validator_test.exs index e771260c9..e6231dbcd 100644 --- a/test/pleroma/web/activity_pub/object_validators/create_generic_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/create_generic_validator_test.exs @@ -59,4 +59,37 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidatorTest do assert validated.valid? assert {:context, note["context"]} in validated.changes end + + test "a Create/Note without addressing falls back to the Note's recipients" do + user = insert(:user) + + note = %{ + "id" => Utils.generate_object_id(), + "type" => "Note", + "actor" => user.ap_id, + "to" => [user.follower_address], + "cc" => [], + "content" => "Hello world", + "context" => Utils.generate_context_id() + } + + note_activity = %{ + "id" => Utils.generate_activity_id(), + "type" => "Create", + "actor" => note["actor"], + "object" => note, + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "context" => Utils.generate_context_id() + } + + # Build metadata + {:ok, object_data} = ObjectValidator.cast_and_apply(note_activity["object"]) + meta = [object_data: ObjectValidator.stringify_keys(object_data)] + + validated = CreateGenericValidator.cast_and_validate(note_activity, meta) + + assert validated.valid? + assert Ecto.Changeset.get_field(validated, :to) == note["to"] + assert Ecto.Changeset.get_field(validated, :cc) == note["cc"] + end end diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index 8fef013bb..f89e34a69 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -123,6 +123,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do assert activity.data["context"] == object.data["context"] end + test "it fixes the public scope addressing" do + insert(:user, + ap_id: "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0" + ) + + object = + "test/fixtures/bovine-bogus-public-note.json" + |> File.read!() + |> Jason.decode!() + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Create", + "actor" => "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0", + "object" => object + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + + object = Object.normalize(activity, fetch: false) + assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] + assert "https://www.w3.org/ns/activitystreams#Public" in object.data["to"] + end + test "it keeps link tags" do insert(:user, ap_id: "https://example.org/users/alice")