Merge branch 'transmogrifier/handle-as-public' into 'develop'

Transmogrifier: convert "as:Public" to full w3 URL

See merge request pleroma/pleroma!4394
This commit is contained in:
lain 2025-12-22 07:39:44 +00:00
commit 1d366c0138
6 changed files with 123 additions and 1 deletions

View file

@ -0,0 +1 @@
Transmogrifier: convert "as:Public" to full w3 URL

View file

@ -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 ->

View file

@ -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

View file

@ -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": "<blockquote class=\"h-quote\">\n<p>I note that mymath.rocks does not provide this information.</p>\n</blockquote>\n<p>I&#39;m a big believer in &quot;Do as I say, not as I <strong>did</strong>&quot;.</p>\n<p>I could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.</p>\n<p>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.</p>\n<p>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&#39;s fix nodeinfo and people will follow their ideas.</p>\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"
}

View file

@ -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

View file

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