Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
30 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
index 4b30fd21d..3d3101d61 100644
--- a/lib/pleroma/web/federator.ex
+++ b/lib/pleroma/web/federator.ex
@@ -1,121 +1,123 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
alias Pleroma.Object.Containment
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Publisher
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Workers.PublisherWorker
alias Pleroma.Workers.ReceiverWorker
require Logger
@behaviour Pleroma.Web.Federator.Publishing
@doc """
Returns `true` if the distance to target object does not exceed max configured value.
Serves to prevent fetching of very long threads, especially useful on smaller instances.
Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161).
Applies to fetching of both ancestor (reply-to) and child (reply) objects.
"""
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
def allowed_thread_distance?(distance) do
max_distance = Pleroma.Config.get([:instance, :federation_incoming_replies_max_depth])
if max_distance && max_distance >= 0 do
# Default depth is 0 (an object has zero distance from itself in its thread)
(distance || 0) <= max_distance
else
true
end
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
def incoming_ap_doc(%{"type" => "Delete"} = params) do
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params}, priority: 3, queue: :slow)
end
def incoming_ap_doc(params) do
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params})
end
@impl true
def publish(%{id: "pleroma:fakeid"} = activity) do
perform(:publish, activity)
end
@impl true
def publish(%Pleroma.Activity{data: %{"type" => type}} = activity) do
PublisherWorker.enqueue("publish", %{"activity_id" => activity.id},
priority: publish_priority(type)
)
end
defp publish_priority("Delete"), do: 3
defp publish_priority(_), do: 0
# Job Worker Callbacks
@spec perform(atom(), any()) :: {:ok, any()} | {:error, any()}
def perform(:publish_one, params), do: Publisher.publish_one(params)
def perform(:publish, activity) do
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
%User{} = actor = User.get_cached_by_ap_id(activity.data["actor"])
Publisher.publish(actor, activity)
end
def perform(:incoming_ap_doc, params) do
Logger.debug("Handling incoming AP activity")
actor =
params
|> Map.get("actor")
|> Utils.get_ap_id()
# NOTE: we use the actor ID to do the containment, this is fine because an
# actor shouldn't be acting on objects outside their own AP server.
with {_, {:ok, _user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
nil <- Activity.normalize(params["id"]),
{_, :ok} <-
{:correct_origin?, Containment.contain_origin_from_id(actor, params)},
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
{:ok, activity}
else
{:correct_origin?, _} ->
Logger.debug("Origin containment failure for #{params["id"]}")
{:error, :origin_containment_failed}
%Activity{} ->
Logger.debug("Already had #{params["id"]}")
{:error, :already_present}
{:actor, e} ->
Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")
{:error, e}
{:error, {:validate_object, _}} = e ->
Logger.error("Incoming AP doc validation error: #{inspect(e)}")
Logger.debug(Jason.encode!(params, pretty: true))
e
e ->
# Just drop those for now
Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)
{:error, e}
end
end
end
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 94624579e..fd5c13fca 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -1,74 +1,74 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.ReceiverWorker do
alias Pleroma.Signature
alias Pleroma.User
alias Pleroma.Web.Federator
use Pleroma.Workers.WorkerHelper, queue: "federator_incoming"
@impl Oban.Worker
def perform(%Job{
args: %{
"op" => "incoming_ap_doc",
"method" => method,
"params" => params,
"req_headers" => req_headers,
"request_path" => request_path,
"query_string" => query_string
}
}) do
# Oban's serialization converts our tuple headers to lists.
# 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,
request_path: request_path,
query_string: query_string
}
with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
{:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
{:ok, res}
else
e -> process_errors(e)
end
end
def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
{:ok, res}
else
e -> process_errors(e)
end
end
@impl Oban.Worker
def timeout(%_{args: %{"timeout" => timeout}}), do: timeout
def timeout(_job), do: :timer.seconds(5)
defp process_errors(errors) do
case errors do
{:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
{:error, :already_present} -> {:cancel, :already_present}
{:error, {:validate_object, _} = reason} -> {:cancel, reason}
{:error, {:error, {:validate, {:error, _changeset} = reason}}} -> {:cancel, reason}
{:error, {:reject, _} = reason} -> {:cancel, reason}
{:signature, false} -> {:cancel, :invalid_signature}
{:error, "Object has been deleted"} = reason -> {:cancel, reason}
{:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
{:error, :not_found} = reason -> {:cancel, reason}
{:error, _} = e -> e
e -> {:error, e}
end
end
end
diff --git a/test/fixtures/bastianallgeier.json b/test/fixtures/bastianallgeier.json
new file mode 100644
index 000000000..6b47e7db9
--- /dev/null
+++ 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 &amp; 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
new file mode 100644
index 000000000..7aa4de508
--- /dev/null
+++ 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
new file mode 100644
index 000000000..3c3fb3fd2
--- /dev/null
+++ 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
index 2b8bd3c40..33be91085 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -1,52 +1,248 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.ReceiverWorkerTest do
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import Mock
import Pleroma.Factory
+ alias Pleroma.Web.Federator
alias Pleroma.Workers.ReceiverWorker
test "it does not retry MRF reject" do
params = insert(:note).data
with_mock Pleroma.Web.ActivityPub.Transmogrifier,
handle_incoming: fn _ -> {:reject, "MRF"} end do
assert {:cancel, {:reject, "MRF"}} =
ReceiverWorker.perform(%Oban.Job{
args: %{"op" => "incoming_ap_doc", "params" => params}
})
end
end
test "it does not retry ObjectValidator reject" do
params =
insert(:note_activity).data
|> Map.put("id", Pleroma.Web.ActivityPub.Utils.generate_activity_id())
|> Map.put("object", %{
"type" => "Note",
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id()
})
with_mock Pleroma.Web.ActivityPub.ObjectValidator, [:passthrough],
validate: fn _, _ -> {:error, %Ecto.Changeset{}} end do
assert {:cancel, {:error, %Ecto.Changeset{}}} =
ReceiverWorker.perform(%Oban.Job{
args: %{"op" => "incoming_ap_doc", "params" => params}
})
end
end
test "it does not retry duplicates" do
params = insert(:note_activity).data
assert {:cancel, :already_present} =
ReceiverWorker.perform(%Oban.Job{
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

File Metadata

Mime Type
text/x-diff
Expires
Thu, Oct 29, 3:50 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1798300
Default Alt Text
(30 KB)

Event Timeline