Transmogrifier: fix reply context fixing
authorHélène <pleroma-dev@helene.moe>
Tue, 2 Aug 2022 15:30:36 +0000 (17:30 +0200)
committerFloatingGhost <hannah@coffee-and-dreams.uk>
Thu, 4 Aug 2022 11:57:48 +0000 (12:57 +0100)
Incoming Pleroma replies to a Misskey thread were rejected due to a
broken context fix, which caused them to not be visible until a
non-Pleroma user interacted with the replies.

This fix properly sets the post-fix object context to its parent Create
activity as well, if it was changed.

lib/pleroma/web/activity_pub/transmogrifier.ex
test/fixtures/create-pleroma-reply-to-misskey-thread.json [new file with mode: 0644]
test/fixtures/tesla_mock/helene@p.helene.moe.json [new file with mode: 0644]
test/fixtures/tesla_mock/mametsuko@mk.absturztau.be.json [new file with mode: 0644]
test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg.json [new file with mode: 0644]
test/fixtures/tesla_mock/p.helene.moe-AM7S6vZQmL6pI9TgPY.json [new file with mode: 0644]
test/pleroma/web/activity_pub/transmogrifier_test.exs
test/support/http_request_mock.ex

index 604fc631093fe026746a746d8804bcd107ec511e..d2077967c31458bf4d10abfa181bf6574c6a4f92 100644 (file)
@@ -474,7 +474,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
       |> fix_in_reply_to(fetch_options)
       |> fix_quote_url(fetch_options)
 
-    data = Map.put(data, "object", object)
+    # Only change the Create's context if the object's context has been modified.
+    data =
+      if data["object"]["context"] != object["context"] do
+        data
+        |> Map.put("object", object)
+        |> Map.put("context", object["context"])
+      else
+        Map.put(data, "object", object)
+      end
+
     options = Keyword.put(options, :local, false)
 
     with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
diff --git a/test/fixtures/create-pleroma-reply-to-misskey-thread.json b/test/fixtures/create-pleroma-reply-to-misskey-thread.json
new file mode 100644 (file)
index 0000000..0c31efa
--- /dev/null
@@ -0,0 +1,61 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://p.helene.moe/schemas/litepub-0.1.jsonld",
+        {
+            "@language": "und"
+        }
+    ],
+    "actor": "https://p.helene.moe/users/helene",
+    "attachment": [],
+    "attributedTo": "https://p.helene.moe/users/helene",
+    "cc": [
+        "https://p.helene.moe/users/helene/followers"
+    ],
+    "context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+    "conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+    "directMessage": false,
+    "id": "https://p.helene.moe/activities/5f80db86-a9bb-4883-9845-fbdbd1478f3a",
+    "object": {
+        "actor": "https://p.helene.moe/users/helene",
+        "attachment": [],
+        "attributedTo": "https://p.helene.moe/users/helene",
+        "cc": [
+            "https://p.helene.moe/users/helene/followers"
+        ],
+        "content": "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"AHntpQ4T3J4OSnpgMC\" href=\"https://mk.absturztau.be/@mametsuko\" rel=\"ugc\">@<span>mametsuko</span></a></span> meow",
+        "context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+        "conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+        "id": "https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4",
+        "inReplyTo": "https://mk.absturztau.be/notes/93e7nm8wqg",
+        "published": "2022-08-02T13:46:58.403996Z",
+        "sensitive": null,
+        "source": "@mametsuko@mk.absturztau.be meow",
+        "summary": "",
+        "tag": [
+            {
+                "href": "https://mk.absturztau.be/users/8ozbzjs3o8",
+                "name": "@mametsuko@mk.absturztau.be",
+                "type": "Mention"
+            }
+        ],
+        "to": [
+            "https://mk.absturztau.be/users/8ozbzjs3o8",
+            "https://www.w3.org/ns/activitystreams#Public"
+        ],
+        "type": "Note"
+    },
+    "published": "2022-08-02T13:46:58.403883Z",
+    "tag": [
+        {
+            "href": "https://mk.absturztau.be/users/8ozbzjs3o8",
+            "name": "@mametsuko@mk.absturztau.be",
+            "type": "Mention"
+        }
+    ],
+    "to": [
+        "https://mk.absturztau.be/users/8ozbzjs3o8",
+        "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "type": "Create"
+}
\ No newline at end of file
diff --git a/test/fixtures/tesla_mock/helene@p.helene.moe.json b/test/fixtures/tesla_mock/helene@p.helene.moe.json
new file mode 100644 (file)
index 0000000..d744481
--- /dev/null
@@ -0,0 +1,50 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://p.helene.moe/schemas/litepub-0.1.jsonld",
+        {
+            "@language": "und"
+        }
+    ],
+    "alsoKnownAs": [],
+    "attachment": [
+        {
+            "name": "Timezone",
+            "type": "PropertyValue",
+            "value": "UTC+2 (Paris/Berlin)"
+        }
+    ],
+    "capabilities": {
+        "acceptsChatMessages": true
+    },
+    "discoverable": true,
+    "endpoints": {
+        "oauthAuthorizationEndpoint": "https://p.helene.moe/oauth/authorize",
+        "oauthRegistrationEndpoint": "https://p.helene.moe/api/v1/apps",
+        "oauthTokenEndpoint": "https://p.helene.moe/oauth/token",
+        "sharedInbox": "https://p.helene.moe/inbox",
+        "uploadMedia": "https://p.helene.moe/api/ap/upload_media"
+    },
+    "featured": "https://p.helene.moe/users/helene/collections/featured",
+    "followers": "https://p.helene.moe/users/helene/followers",
+    "following": "https://p.helene.moe/users/helene/following",
+    "icon": {
+        "type": "Image",
+        "url": "https://p.helene.moe/media/9a39209daa5a66b7ebb0547b08bf8360aa9d8d65a4ffba2603c6ffbe6aecb432.jpg"
+    },
+    "id": "https://p.helene.moe/users/helene",
+    "inbox": "https://p.helene.moe/users/helene/inbox",
+    "manuallyApprovesFollowers": false,
+    "name": "Hélène",
+    "outbox": "https://p.helene.moe/users/helene/outbox",
+    "preferredUsername": "helene",
+    "publicKey": {
+        "id": "https://p.helene.moe/users/helene#main-key",
+        "owner": "https://p.helene.moe/users/helene",
+        "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtoSBPU/VS2Kx3f6ap3zv\nZVacJsgUfaoFb3c2ii/FRh9RmRVlarq8sJXcjsQt1e0oxWaWJaIDDwyKZPt6hXae\nrY/AiGGeNu+NA+BtY7l7+9Yu67HUyT62+1qAwYHKBXX3fLOPs/YmQI0Tt0c4wKAG\nKEkiYsRizghgpzUC6jqdKV71DJkUZ8yhckCGb2fLko1ajbWEssdaP51aLsyRMyC2\nuzeWrxtD4O/HG0ea4S6y5X6hnsAHIK4Y3nnyIQ6pn4tOsl3HgqkjXE9MmZSvMCFx\nBq89TfZrVXNa2gSZdZLdbbJstzEScQWNt1p6tA6rM+e4JXYGr+rMdF3G+jV7afI2\nFQIDAQAB\n-----END PUBLIC KEY-----\n\n"
+    },
+    "summary": "I can speak: Français, English, Deutsch (nicht sehr gut), 日本語 (not very well)",
+    "tag": [],
+    "type": "Person",
+    "url": "https://p.helene.moe/users/helene"
+}
\ No newline at end of file
diff --git a/test/fixtures/tesla_mock/mametsuko@mk.absturztau.be.json b/test/fixtures/tesla_mock/mametsuko@mk.absturztau.be.json
new file mode 100644 (file)
index 0000000..d8c13f7
--- /dev/null
@@ -0,0 +1,65 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://w3id.org/security/v1",
+        {
+            "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+            "sensitive": "as:sensitive",
+            "Hashtag": "as:Hashtag",
+            "quoteUrl": "as:quoteUrl",
+            "toot": "http://joinmastodon.org/ns#",
+            "Emoji": "toot:Emoji",
+            "featured": "toot:featured",
+            "discoverable": "toot:discoverable",
+            "schema": "http://schema.org#",
+            "PropertyValue": "schema:PropertyValue",
+            "value": "schema:value",
+            "misskey": "https://misskey-hub.net/ns#",
+            "_misskey_content": "misskey:_misskey_content",
+            "_misskey_quote": "misskey:_misskey_quote",
+            "_misskey_reaction": "misskey:_misskey_reaction",
+            "_misskey_votes": "misskey:_misskey_votes",
+            "_misskey_talk": "misskey:_misskey_talk",
+            "isCat": "misskey:isCat",
+            "vcard": "http://www.w3.org/2006/vcard/ns#"
+        }
+    ],
+    "type": "Person",
+    "id": "https://mk.absturztau.be/users/8ozbzjs3o8",
+    "inbox": "https://mk.absturztau.be/users/8ozbzjs3o8/inbox",
+    "outbox": "https://mk.absturztau.be/users/8ozbzjs3o8/outbox",
+    "followers": "https://mk.absturztau.be/users/8ozbzjs3o8/followers",
+    "following": "https://mk.absturztau.be/users/8ozbzjs3o8/following",
+    "featured": "https://mk.absturztau.be/users/8ozbzjs3o8/collections/featured",
+    "sharedInbox": "https://mk.absturztau.be/inbox",
+    "endpoints": {
+        "sharedInbox": "https://mk.absturztau.be/inbox"
+    },
+    "url": "https://mk.absturztau.be/@mametsuko",
+    "preferredUsername": "mametsuko",
+    "name": "mametschko",
+    "summary": "<p><span>nya, ich bin eine Brotperson</span></p>",
+    "icon": {
+        "type": "Image",
+        "url": "https://mk.absturztau.be/files/webpublic-3b5594f4-fa52-4548-b4e3-c379ae2143ed",
+        "sensitive": false,
+        "name": null
+    },
+    "image": {
+        "type": "Image",
+        "url": "https://mk.absturztau.be/files/webpublic-0d03b03d-b14b-4916-ac3d-8a137118ec84",
+        "sensitive": false,
+        "name": null
+    },
+    "tag": [],
+    "manuallyApprovesFollowers": true,
+    "discoverable": false,
+    "publicKey": {
+        "id": "https://mk.absturztau.be/users/8ozbzjs3o8#main-key",
+        "type": "Key",
+        "owner": "https://mk.absturztau.be/users/8ozbzjs3o8",
+        "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuN/S1spBGmh8FXI1Bt16\nXB7Cc0QutBp7UPgmDNHjOfsq0zrF4g3L1UBxvrpU0XX77XPMCd9yPvGwAYURH2mv\ntIcYuE+R90VLDmBu5MTVthcG2D874eCZ2rD2YsEYmN5AjTX7QBIqCck+qDhVWkkM\nEZ6S5Ht6IJ5Of74eKffXElQI/C6QB+9uEDOmPk0jCzgI5gw7xvJqFj/DIF4kUUAu\nA89JqaFZzZlkrSrj4cr48bLN/YOmpdaHu0BKHaDSHct4+MqlixqovgdB6RboCEDw\ne4Aeav7+Q0Y9oGIvuggg0Q+nCubnVNnaPyzd817tpPVzyZmTts+DKyDuv90SX3nR\nsPaNa5Ty60eqplUk4b7X1gSvuzBJUFBxTVV84WnjwoeoydaS6rSyjCDPGLBjaByc\nFyWMMEb/zlQyhLZfBlvT7k96wRSsMszh2hDALWmgYIhq/jNwINvALJ1GKLNHHKZ4\nyz2LnxVpRm2rWrZzbvtcnSQOt3LaPSZn8Wgwv4buyHF02iuVuIamZVtKexsE1Ixl\nIi9qa3AKEc5gOzYXhRhvHaruzoCehUbb/UHC5c8Tto8L5G1xYzjLP3qj3PT9w/wM\n+k1Ra/4JhuAnVFROOoOmx9rIELLHH7juY2nhM7plGhyt1M5gysgqEloij8QzyQU2\nZK1YlAERG2XFO6br8omhcmECAwEAAQ==\n-----END PUBLIC KEY-----\n"
+    },
+    "isCat": true,
+    "vcard:Address": "Vienna, Austria"
+}
\ No newline at end of file
diff --git a/test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg.json b/test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg.json
new file mode 100644 (file)
index 0000000..1b931a9
--- /dev/null
@@ -0,0 +1,44 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://w3id.org/security/v1",
+        {
+            "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+            "sensitive": "as:sensitive",
+            "Hashtag": "as:Hashtag",
+            "quoteUrl": "as:quoteUrl",
+            "toot": "http://joinmastodon.org/ns#",
+            "Emoji": "toot:Emoji",
+            "featured": "toot:featured",
+            "discoverable": "toot:discoverable",
+            "schema": "http://schema.org#",
+            "PropertyValue": "schema:PropertyValue",
+            "value": "schema:value",
+            "misskey": "https://misskey-hub.net/ns#",
+            "_misskey_content": "misskey:_misskey_content",
+            "_misskey_quote": "misskey:_misskey_quote",
+            "_misskey_reaction": "misskey:_misskey_reaction",
+            "_misskey_votes": "misskey:_misskey_votes",
+            "_misskey_talk": "misskey:_misskey_talk",
+            "isCat": "misskey:isCat",
+            "vcard": "http://www.w3.org/2006/vcard/ns#"
+        }
+    ],
+    "id": "https://mk.absturztau.be/notes/93e7nm8wqg",
+    "type": "Note",
+    "attributedTo": "https://mk.absturztau.be/users/8ozbzjs3o8",
+    "summary": null,
+    "content": "<p><span>meow</span></p>",
+    "_misskey_content": "meow",
+    "published": "2022-08-01T11:06:49.568Z",
+    "to": [
+        "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "cc": [
+        "https://mk.absturztau.be/users/8ozbzjs3o8/followers"
+    ],
+    "inReplyTo": null,
+    "attachment": [],
+    "sensitive": false,
+    "tag": []
+}
\ No newline at end of file
diff --git a/test/fixtures/tesla_mock/p.helene.moe-AM7S6vZQmL6pI9TgPY.json b/test/fixtures/tesla_mock/p.helene.moe-AM7S6vZQmL6pI9TgPY.json
new file mode 100644 (file)
index 0000000..a1ef5e2
--- /dev/null
@@ -0,0 +1,36 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://p.helene.moe/schemas/litepub-0.1.jsonld",
+        {
+            "@language": "und"
+        }
+    ],
+    "actor": "https://p.helene.moe/users/helene",
+    "attachment": [],
+    "attributedTo": "https://p.helene.moe/users/helene",
+    "cc": [
+        "https://p.helene.moe/users/helene/followers"
+    ],
+    "content": "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"AHntpQ4T3J4OSnpgMC\" href=\"https://mk.absturztau.be/@mametsuko\" rel=\"ugc\">@<span>mametsuko</span></a></span> meow",
+    "context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+    "conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
+    "id": "https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4",
+    "inReplyTo": "https://mk.absturztau.be/notes/93e7nm8wqg",
+    "published": "2022-08-02T13:46:58.403996Z",
+    "sensitive": null,
+    "source": "@mametsuko@mk.absturztau.be meow",
+    "summary": "",
+    "tag": [
+        {
+            "href": "https://mk.absturztau.be/users/8ozbzjs3o8",
+            "name": "@mametsuko@mk.absturztau.be",
+            "type": "Mention"
+        }
+    ],
+    "to": [
+        "https://mk.absturztau.be/users/8ozbzjs3o8",
+        "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "type": "Note"
+}
\ No newline at end of file
index 3756fdee0123d7b5c3f953defab97eac9b717810..6941f69aaf935cdd236d3c9acdc2339801630794 100644 (file)
@@ -107,6 +107,22 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert activity.data["target"] == new_user.ap_id
       assert activity.data["type"] == "Move"
     end
+
+    test "it fixes both the Create and object contexts in a reply" do
+      insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
+      insert(:user, ap_id: "https://p.helene.moe/users/helene")
+
+      create_activity =
+        "test/fixtures/create-pleroma-reply-to-misskey-thread.json"
+        |> File.read!()
+        |> Jason.decode!()
+
+      assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(create_activity)
+
+      object = Object.normalize(activity, fetch: false)
+
+      assert activity.data["context"] == object.data["context"]
+    end
   end
 
   describe "prepare outgoing" do
index 42dcb2bc3ce33ca5655e1fad2adf10f22d3b07b8..476e0ce04537f986ba3e46cd25f8a48e29a2b3df 100644 (file)
@@ -1363,6 +1363,42 @@ defmodule HttpRequestMock do
      }}
   end
 
+  def get("https://mk.absturztau.be/users/8ozbzjs3o8", _, _, _) do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/mametsuko@mk.absturztau.be.json"),
+       headers: activitypub_object_headers()
+     }}
+  end
+
+  def get("https://p.helene.moe/users/helene", _, _, _) do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/helene@p.helene.moe.json"),
+       headers: activitypub_object_headers()
+     }}
+  end
+
+  def get("https://mk.absturztau.be/notes/93e7nm8wqg", _, _, _) do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg.json"),
+       headers: activitypub_object_headers()
+     }}
+  end
+
+  def get("https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4", _, _, _) do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/p.helene.moe-AM7S6vZQmL6pI9TgPY.json"),
+       headers: activitypub_object_headers()
+     }}
+  end
+
   def get(url, query, body, headers) do
     {:error,
      "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}