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

I note that mymath.rocks does not provide this information.

\n
\n

I'm a big believer in "Do as I say, not as I did".

\n

I could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.

\n

I 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

I 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")