commit: a964368e31ddf8a22dd36bbf2aae51f7d91bbdaf
parent 1b9c887dbb8d87814f8d9cc11cfcbc8802348b22
Author: Mark Felder <feld@feld.me>
Date:   Thu, 25 Jul 2024 14:33:51 -0400
Add test to fetch and validate an activity that originally failed signature
Diffstat:
6 files changed, 492 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
@@ -35,10 +35,12 @@ defmodule Pleroma.Web.Federator do
   end
 
   # Client API
-  def incoming_ap_doc(%{params: params, req_headers: req_headers}) do
+  def incoming_ap_doc(%{params: _params, req_headers: _req_headers} = args) do
+    job_args = Enum.into(args, %{}, fn {k, v} -> {Atom.to_string(k), v} end)
+
     ReceiverWorker.enqueue(
       "incoming_ap_doc",
-      %{"req_headers" => req_headers, "params" => params, "timeout" => :timer.seconds(20)},
+      Map.put(job_args, "timeout", :timer.seconds(20)),
       priority: 2
     )
   end
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
@@ -25,7 +25,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
     # Revert it for the signature validation.
     req_headers = Enum.into(req_headers, [], &List.to_tuple(&1))
 
-    conn_data = %{
+    conn_data = %Plug.Conn{
       method: method,
       params: params,
       req_headers: req_headers,
diff --git a/test/fixtures/bastianallgeier.json b/test/fixtures/bastianallgeier.json
@@ -0,0 +1,117 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "Curve25519Key": "toot:Curve25519Key",
+      "Device": "toot:Device",
+      "Ed25519Key": "toot:Ed25519Key",
+      "Ed25519Signature": "toot:Ed25519Signature",
+      "EncryptedMessage": "toot:EncryptedMessage",
+      "PropertyValue": "schema:PropertyValue",
+      "alsoKnownAs": {
+        "@id": "as:alsoKnownAs",
+        "@type": "@id"
+      },
+      "cipherText": "toot:cipherText",
+      "claim": {
+        "@id": "toot:claim",
+        "@type": "@id"
+      },
+      "deviceId": "toot:deviceId",
+      "devices": {
+        "@id": "toot:devices",
+        "@type": "@id"
+      },
+      "discoverable": "toot:discoverable",
+      "featured": {
+        "@id": "toot:featured",
+        "@type": "@id"
+      },
+      "featuredTags": {
+        "@id": "toot:featuredTags",
+        "@type": "@id"
+      },
+      "fingerprintKey": {
+        "@id": "toot:fingerprintKey",
+        "@type": "@id"
+      },
+      "focalPoint": {
+        "@container": "@list",
+        "@id": "toot:focalPoint"
+      },
+      "identityKey": {
+        "@id": "toot:identityKey",
+        "@type": "@id"
+      },
+      "indexable": "toot:indexable",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "memorial": "toot:memorial",
+      "messageFranking": "toot:messageFranking",
+      "messageType": "toot:messageType",
+      "movedTo": {
+        "@id": "as:movedTo",
+        "@type": "@id"
+      },
+      "publicKeyBase64": "toot:publicKeyBase64",
+      "schema": "http://schema.org#",
+      "suspended": "toot:suspended",
+      "toot": "http://joinmastodon.org/ns#",
+      "value": "schema:value"
+    }
+  ],
+  "attachment": [
+    {
+      "name": "Website",
+      "type": "PropertyValue",
+      "value": "<a href=\"https://bastianallgeier.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">bastianallgeier.com</span><span class=\"invisible\"></span></a>"
+    },
+    {
+      "name": "Project",
+      "type": "PropertyValue",
+      "value": "<a href=\"https://getkirby.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">getkirby.com</span><span class=\"invisible\"></span></a>"
+    },
+    {
+      "name": "Github",
+      "type": "PropertyValue",
+      "value": "<a href=\"https://github.com/bastianallgeier\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">github.com/bastianallgeier</span><span class=\"invisible\"></span></a>"
+    }
+  ],
+  "devices": "https://mastodon.social/users/bastianallgeier/collections/devices",
+  "discoverable": true,
+  "endpoints": {
+    "sharedInbox": "https://mastodon.social/inbox"
+  },
+  "featured": "https://mastodon.social/users/bastianallgeier/collections/featured",
+  "featuredTags": "https://mastodon.social/users/bastianallgeier/collections/tags",
+  "followers": "https://mastodon.social/users/bastianallgeier/followers",
+  "following": "https://mastodon.social/users/bastianallgeier/following",
+  "icon": {
+    "mediaType": "image/jpeg",
+    "type": "Image",
+    "url": "https://files.mastodon.social/accounts/avatars/000/007/393/original/0180a20079617c71.jpg"
+  },
+  "id": "https://mastodon.social/users/bastianallgeier",
+  "image": {
+    "mediaType": "image/jpeg",
+    "type": "Image",
+    "url": "https://files.mastodon.social/accounts/headers/000/007/393/original/13d644ab46d50478.jpeg"
+  },
+  "inbox": "https://mastodon.social/users/bastianallgeier/inbox",
+  "indexable": false,
+  "manuallyApprovesFollowers": false,
+  "memorial": false,
+  "name": "Bastian Allgeier",
+  "outbox": "https://mastodon.social/users/bastianallgeier/outbox",
+  "preferredUsername": "bastianallgeier",
+  "publicKey": {
+    "id": "https://mastodon.social/users/bastianallgeier#main-key",
+    "owner": "https://mastodon.social/users/bastianallgeier",
+    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fz+hpgVztO9z6HUhyzv\nwP++ERBBoIwSLKf1TyIM8bvzGFm2YXaO5uxu1HvumYFTYc3ACr3q4j8VUb7NMxkQ\nlzu4QwPjOFJ43O+fY+HSPORXEDW5fXDGC5DGpox4+i08LxRmx7L6YPRUSUuPN8nI\nWyq1Qsq1zOQrNY/rohMXkBdSXxqC3yIRqvtLt4otCgay/5tMogJWkkS6ZKyFhb9z\nwVVy1fsbV10c9C+SHy4NH26CKaTtpTYLRBMjhTCS8bX8iDSjGIf2aZgYs1ir7gEz\n9wf5CvLiENmVWGwm64t6KSEAkA4NJ1hzgHUZPCjPHZE2SmhO/oHaxokTzqtbbENJ\n1QIDAQAB\n-----END PUBLIC KEY-----\n"
+  },
+  "published": "2016-11-01T00:00:00Z",
+  "summary": "<p>Designer & developer. Creator of Kirby CMS</p>",
+  "tag": [],
+  "type": "Person",
+  "url": "https://mastodon.social/@bastianallgeier"
+}
diff --git a/test/fixtures/denniskoch.json b/test/fixtures/denniskoch.json
@@ -0,0 +1,112 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "Curve25519Key": "toot:Curve25519Key",
+      "Device": "toot:Device",
+      "Ed25519Key": "toot:Ed25519Key",
+      "Ed25519Signature": "toot:Ed25519Signature",
+      "EncryptedMessage": "toot:EncryptedMessage",
+      "PropertyValue": "schema:PropertyValue",
+      "alsoKnownAs": {
+        "@id": "as:alsoKnownAs",
+        "@type": "@id"
+      },
+      "cipherText": "toot:cipherText",
+      "claim": {
+        "@id": "toot:claim",
+        "@type": "@id"
+      },
+      "deviceId": "toot:deviceId",
+      "devices": {
+        "@id": "toot:devices",
+        "@type": "@id"
+      },
+      "discoverable": "toot:discoverable",
+      "featured": {
+        "@id": "toot:featured",
+        "@type": "@id"
+      },
+      "featuredTags": {
+        "@id": "toot:featuredTags",
+        "@type": "@id"
+      },
+      "fingerprintKey": {
+        "@id": "toot:fingerprintKey",
+        "@type": "@id"
+      },
+      "focalPoint": {
+        "@container": "@list",
+        "@id": "toot:focalPoint"
+      },
+      "identityKey": {
+        "@id": "toot:identityKey",
+        "@type": "@id"
+      },
+      "indexable": "toot:indexable",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "memorial": "toot:memorial",
+      "messageFranking": "toot:messageFranking",
+      "messageType": "toot:messageType",
+      "movedTo": {
+        "@id": "as:movedTo",
+        "@type": "@id"
+      },
+      "publicKeyBase64": "toot:publicKeyBase64",
+      "schema": "http://schema.org#",
+      "suspended": "toot:suspended",
+      "toot": "http://joinmastodon.org/ns#",
+      "value": "schema:value"
+    }
+  ],
+  "attachment": [
+    {
+      "name": "GitHub",
+      "type": "PropertyValue",
+      "value": "<a href=\"https://github.com/pxlrbt/\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">github.com/pxlrbt/</span><span class=\"invisible\"></span></a>"
+    },
+    {
+      "name": "Discord",
+      "type": "PropertyValue",
+      "value": "pxlrbt#6029"
+    }
+  ],
+  "devices": "https://phpc.social/users/denniskoch/collections/devices",
+  "discoverable": true,
+  "endpoints": {
+    "sharedInbox": "https://phpc.social/inbox"
+  },
+  "featured": "https://phpc.social/users/denniskoch/collections/featured",
+  "featuredTags": "https://phpc.social/users/denniskoch/collections/tags",
+  "followers": "https://phpc.social/users/denniskoch/followers",
+  "following": "https://phpc.social/users/denniskoch/following",
+  "icon": {
+    "mediaType": "image/jpeg",
+    "type": "Image",
+    "url": "https://media.phpc.social/accounts/avatars/109/364/097/179/042/485/original/6e770c7b3f5ef72d.jpg"
+  },
+  "id": "https://phpc.social/users/denniskoch",
+  "image": {
+    "mediaType": "image/jpeg",
+    "type": "Image",
+    "url": "https://media.phpc.social/accounts/headers/109/364/097/179/042/485/original/709da24705260c04.jpg"
+  },
+  "inbox": "https://phpc.social/users/denniskoch/inbox",
+  "indexable": true,
+  "manuallyApprovesFollowers": false,
+  "memorial": false,
+  "name": "Dennis Koch",
+  "outbox": "https://phpc.social/users/denniskoch/outbox",
+  "preferredUsername": "denniskoch",
+  "publicKey": {
+    "id": "https://phpc.social/users/denniskoch#main-key",
+    "owner": "https://phpc.social/users/denniskoch",
+    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dmcSlqLj18gPvuslkmt\nQTniZ8ybO4pgvMvPLYtBuTBUjo49vJ/8Sw6jB5zcKb1haqIdny7Rv/vY3kCdCXcP\nloh1I+jthEgqLT8JpZWGwLGwg9piFhrMGADmt3N8du7HfglzuZ8LlVpnZ8feCw7I\nS2ua/ZCxE47mI45Z3ed2kkFYKWopWWqFn2lan/1OyHrcFKtCvaVjRdvo0UUt2tgl\nvyJI4+zN8FnrCbsMtcbI5nSzfJIrOc4LeaGmLJh+0o2rwoOQZc2487XWbeyfhjsq\nPRBpYN7pfHWQDvzQIN075LHTf9zDFsm6+HqY7Zs5rYxr72rvcX7d9JcP6CasIosY\nqwIDAQAB\n-----END PUBLIC KEY-----\n"
+  },
+  "published": "2022-11-18T00:00:00Z",
+  "summary": "<p>🧑💻 Full Stack Developer<br />🚀 Laravel, Filament, Livewire, Vue, Inertia<br />🌍 Germany</p>",
+  "tag": [],
+  "type": "Person",
+  "url": "https://phpc.social/@denniskoch"
+}
diff --git a/test/fixtures/receiver_worker_signature_activity.json b/test/fixtures/receiver_worker_signature_activity.json
@@ -0,0 +1,62 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    {
+      "atomUri": "ostatus:atomUri",
+      "blurhash": "toot:blurhash",
+      "conversation": "ostatus:conversation",
+      "focalPoint": {
+        "@container": "@list",
+        "@id": "toot:focalPoint"
+      },
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "ostatus": "http://ostatus.org#",
+      "sensitive": "as:sensitive",
+      "toot": "http://joinmastodon.org/ns#",
+      "votersCount": "toot:votersCount"
+    }
+  ],
+  "atomUri": "https://chaos.social/users/distantnative/statuses/109336635639931467",
+  "attachment": [
+    {
+      "blurhash": "UAK1zS00OXIUxuMxIUM{?b-:-;W:Di?b%2M{",
+      "height": 960,
+      "mediaType": "image/jpeg",
+      "name": null,
+      "type": "Document",
+      "url": "https://assets.chaos.social/media_attachments/files/109/336/634/286/114/657/original/2e6122063d8bfb26.jpeg",
+      "width": 346
+    }
+  ],
+  "attributedTo": "https://chaos.social/users/distantnative",
+  "cc": [
+    "https://chaos.social/users/distantnative/followers"
+  ],
+  "content": "<p>Favorite piece of anthropology meta discourse.</p>",
+  "contentMap": {
+    "en": "<p>Favorite piece of anthropology meta discourse.</p>"
+  },
+  "conversation": "tag:chaos.social,2022-11-13:objectId=71843781:objectType=Conversation",
+  "id": "https://chaos.social/users/distantnative/statuses/109336635639931467",
+  "inReplyTo": null,
+  "inReplyToAtomUri": null,
+  "published": "2022-11-13T13:04:20Z",
+  "replies": {
+    "first": {
+      "items": [],
+      "next": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies?only_other_accounts=true&page=true",
+      "partOf": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies",
+      "type": "CollectionPage"
+    },
+    "id": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies",
+    "type": "Collection"
+  },
+  "sensitive": false,
+  "summary": null,
+  "tag": [],
+  "to": [
+    "https://www.w3.org/ns/activitystreams#Public"
+  ],
+  "type": "Note",
+  "url": "https://chaos.social/@distantnative/109336635639931467"
+}
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
@@ -9,6 +9,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
   import Mock
   import Pleroma.Factory
 
+  alias Pleroma.Web.Federator
   alias Pleroma.Workers.ReceiverWorker
 
   test "it does not retry MRF reject" do
@@ -49,4 +50,199 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
                args: %{"op" => "incoming_ap_doc", "params" => params}
              })
   end
+
+  test "it can validate the signature" do
+    Tesla.Mock.mock(fn
+      %{url: "https://mastodon.social/users/bastianallgeier"} ->
+        %Tesla.Env{
+          status: 200,
+          body: File.read!("test/fixtures/bastianallgeier.json"),
+          headers: [{"content-type", "application/activity+json"}]
+        }
+
+      %{url: "https://mastodon.social/users/bastianallgeier/collections/featured"} ->
+        %Tesla.Env{
+          status: 200,
+          headers: [{"content-type", "application/activity+json"}],
+          body:
+            File.read!("test/fixtures/users_mock/masto_featured.json")
+            |> String.replace("{{domain}}", "mastodon.social")
+            |> String.replace("{{nickname}}", "bastianallgeier")
+        }
+
+      %{url: "https://phpc.social/users/denniskoch"} ->
+        %Tesla.Env{
+          status: 200,
+          body: File.read!("test/fixtures/denniskoch.json"),
+          headers: [{"content-type", "application/activity+json"}]
+        }
+
+      %{url: "https://phpc.social/users/denniskoch/collections/featured"} ->
+        %Tesla.Env{
+          status: 200,
+          headers: [{"content-type", "application/activity+json"}],
+          body:
+            File.read!("test/fixtures/users_mock/masto_featured.json")
+            |> String.replace("{{domain}}", "phpc.social")
+            |> String.replace("{{nickname}}", "denniskoch")
+        }
+
+      %{url: "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281"} ->
+        %Tesla.Env{
+          status: 200,
+          headers: [{"content-type", "application/activity+json"}],
+          body: File.read!("test/fixtures/receiver_worker_signature_activity.json")
+        }
+    end)
+
+    params = %{
+      "@context" => [
+        "https://www.w3.org/ns/activitystreams",
+        "https://w3id.org/security/v1",
+        %{
+          "claim" => %{"@id" => "toot:claim", "@type" => "@id"},
+          "memorial" => "toot:memorial",
+          "atomUri" => "ostatus:atomUri",
+          "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers",
+          "blurhash" => "toot:blurhash",
+          "ostatus" => "http://ostatus.org#",
+          "discoverable" => "toot:discoverable",
+          "focalPoint" => %{"@container" => "@list", "@id" => "toot:focalPoint"},
+          "votersCount" => "toot:votersCount",
+          "Hashtag" => "as:Hashtag",
+          "Emoji" => "toot:Emoji",
+          "alsoKnownAs" => %{"@id" => "as:alsoKnownAs", "@type" => "@id"},
+          "sensitive" => "as:sensitive",
+          "movedTo" => %{"@id" => "as:movedTo", "@type" => "@id"},
+          "inReplyToAtomUri" => "ostatus:inReplyToAtomUri",
+          "conversation" => "ostatus:conversation",
+          "Device" => "toot:Device",
+          "schema" => "http://schema.org#",
+          "toot" => "http://joinmastodon.org/ns#",
+          "cipherText" => "toot:cipherText",
+          "suspended" => "toot:suspended",
+          "messageType" => "toot:messageType",
+          "featuredTags" => %{"@id" => "toot:featuredTags", "@type" => "@id"},
+          "Curve25519Key" => "toot:Curve25519Key",
+          "deviceId" => "toot:deviceId",
+          "Ed25519Signature" => "toot:Ed25519Signature",
+          "featured" => %{"@id" => "toot:featured", "@type" => "@id"},
+          "devices" => %{"@id" => "toot:devices", "@type" => "@id"},
+          "value" => "schema:value",
+          "PropertyValue" => "schema:PropertyValue",
+          "messageFranking" => "toot:messageFranking",
+          "publicKeyBase64" => "toot:publicKeyBase64",
+          "identityKey" => %{"@id" => "toot:identityKey", "@type" => "@id"},
+          "Ed25519Key" => "toot:Ed25519Key",
+          "indexable" => "toot:indexable",
+          "EncryptedMessage" => "toot:EncryptedMessage",
+          "fingerprintKey" => %{"@id" => "toot:fingerprintKey", "@type" => "@id"}
+        }
+      ],
+      "actor" => "https://phpc.social/users/denniskoch",
+      "cc" => [
+        "https://phpc.social/users/denniskoch/followers",
+        "https://mastodon.social/users/bastianallgeier",
+        "https://chaos.social/users/distantnative",
+        "https://fosstodon.org/users/kev"
+      ],
+      "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/activity",
+      "object" => %{
+        "atomUri" => "https://phpc.social/users/denniskoch/statuses/112847382711461301",
+        "attachment" => [],
+        "attributedTo" => "https://phpc.social/users/denniskoch",
+        "cc" => [
+          "https://phpc.social/users/denniskoch/followers",
+          "https://mastodon.social/users/bastianallgeier",
+          "https://chaos.social/users/distantnative",
+          "https://fosstodon.org/users/kev"
+        ],
+        "content" =>
+          "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>",
+        "contentMap" => %{
+          "en" =>
+            "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>"
+        },
+        "conversation" =>
+          "tag:mastodon.social,2024-07-25:objectId=760068442:objectType=Conversation",
+        "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301",
+        "inReplyTo" =>
+          "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281",
+        "inReplyToAtomUri" =>
+          "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281",
+        "published" => "2024-07-25T13:33:29Z",
+        "replies" => %{
+          "first" => %{
+            "items" => [],
+            "next" =>
+              "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies?only_other_accounts=true&page=true",
+            "partOf" =>
+              "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies",
+            "type" => "CollectionPage"
+          },
+          "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies",
+          "type" => "Collection"
+        },
+        "sensitive" => false,
+        "tag" => [
+          %{
+            "href" => "https://mastodon.social/users/bastianallgeier",
+            "name" => "@bastianallgeier@mastodon.social",
+            "type" => "Mention"
+          },
+          %{
+            "href" => "https://chaos.social/users/distantnative",
+            "name" => "@distantnative@chaos.social",
+            "type" => "Mention"
+          },
+          %{
+            "href" => "https://fosstodon.org/users/kev",
+            "name" => "@kev@fosstodon.org",
+            "type" => "Mention"
+          }
+        ],
+        "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+        "type" => "Note",
+        "url" => "https://phpc.social/@denniskoch/112847382711461301"
+      },
+      "published" => "2024-07-25T13:33:29Z",
+      "signature" => %{
+        "created" => "2024-07-25T13:33:29Z",
+        "creator" => "https://phpc.social/users/denniskoch#main-key",
+        "signatureValue" =>
+          "slz9BKJzd2n1S44wdXGOU+bV/wsskdgAaUpwxj8R16mYOL8+DTpE6VnfSKoZGsBBJT8uG5gnVfVEz1YsTUYtymeUgLMh7cvd8VnJnZPS+oixbmBRVky/Myf91TEgQQE7G4vDmTdB4ii54hZrHcOOYYf5FKPNRSkMXboKA6LMqNtekhbI+JTUJYIB02WBBK6PUyo15f6B1RJ6HGWVgud9NE0y1EZXfrkqUt682p8/9D49ORf7AwjXUJibKic2RbPvhEBj70qUGfBm4vvgdWhSUn1IG46xh+U0+NrTSUED82j1ZVOeua/2k/igkGs8cSBkY35quXTkPz6gbqCCH66CuA==",
+        "type" => "RsaSignature2017"
+      },
+      "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+      "type" => "Create"
+    }
+
+    req_headers = [
+      ["accept-encoding", "gzip"],
+      ["content-length", "5184"],
+      ["content-type", "application/activity+json"],
+      ["date", "Thu, 25 Jul 2024 13:33:31 GMT"],
+      ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="],
+      ["host", "bikeshed.party"],
+      [
+        "signature",
+        "keyId=\"https://mastodon.social/users/bastianallgeier#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"ymE3vn5Iw50N6ukSp8oIuXJB5SBjGAGjBasdTDvn+ahZIzq2SIJfmVCsIIzyqIROnhWyQoTbavTclVojEqdaeOx+Ejz2wBnRBmhz5oemJLk4RnnCH0lwMWyzeY98YAvxi9Rq57Gojuv/1lBqyGa+rDzynyJpAMyFk17XIZpjMKuTNMCbjMDy76ILHqArykAIL/v1zxkgwxY/+ELzxqMpNqtZ+kQ29znNMUBB3eVZ/mNAHAz6o33Y9VKxM2jw+08vtuIZOusXyiHbRiaj2g5HtN2WBUw1MzzfRfHF2/yy7rcipobeoyk5RvP5SyHV3WrIeZ3iyoNfmv33y8fxllF0EA==\""
+      ],
+      [
+        "user-agent",
+        "http.rb/5.2.0 (Mastodon/4.3.0-nightly.2024-07-25; +https://mastodon.social/)"
+      ]
+    ]
+
+    {:ok, oban_job} =
+      Federator.incoming_ap_doc(%{
+        method: "POST",
+        req_headers: req_headers,
+        request_path: "/inbox",
+        params: params,
+        query_string: ""
+      })
+
+    assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job)
+  end
 end