From fc450fdefc2df2bbec20a79fb2c60a95e7f41833 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 28 Aug 2024 15:45:13 -0400 Subject: [PATCH] ReceiverWorker: cancel job if user fetch is forbidden An instance block with authenticated fetch being required can cause this as we couldn't get the user to find their public key to verify the signature. Commonly observed if someone boosts/Announces a post from an instance that blocked you. --- lib/pleroma/workers/receiver_worker.ex | 5 +- test/pleroma/workers/receiver_worker_test.exs | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index d4db97b639..7dce02a5fc 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -56,17 +56,20 @@ def timeout(%_{args: %{"timeout" => timeout}}), do: timeout def timeout(_job), do: :timer.seconds(5) + defp process_errors({:error, {:error, _} = error}), do: process_errors(error) + 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, {: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, :forbidden} = reason -> {:cancel, reason} {:error, _} = e -> e e -> {:error, e} end diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs index 33be910853..640cefb785 100644 --- a/test/pleroma/workers/receiver_worker_test.exs +++ b/test/pleroma/workers/receiver_worker_test.exs @@ -51,6 +51,54 @@ test "it does not retry duplicates" do }) end + test "it does not retry if a user fetch fails with a 403" do + Tesla.Mock.mock(fn + %{url: "https://simpsons.com/users/bart"} -> + %Tesla.Env{ + status: 403, + body: "" + } + end) + + params = + %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1" + ], + "actor" => "https://simpsons.com/users/bart", + "cc" => [], + "id" => "https://simpsons.com/activity/eat-my-shorts", + "object" => %{}, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create" + } + + req_headers = [ + ["accept-encoding", "gzip"], + ["content-length", "31337"], + ["content-type", "application/activity+json"], + ["date", "Wed, 28 Aug 2024 15:36:31 GMT"], + ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="], + ["host", "bikeshed.party"], + [ + "signature", + "does not matter as user needs to be fetched first" + ] + ] + + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: req_headers, + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, {:error, :forbidden}} = ReceiverWorker.perform(oban_job) + end + test "it can validate the signature" do Tesla.Mock.mock(fn %{url: "https://mastodon.social/users/bastianallgeier"} ->