Fix Optimistic Inbox for failed signatures

When signatures fail on incoming activities we put the job into Oban to be processed later instead of doing the user fetching and validation inline which is expensive and increases latency on the incoming POST request. Unfortunately we did not retain the :method, :request_path, and :query_string parameters from the conn so the signature validation and Oban Job would always fail.

This was most obvious when Mastodon sends Deletes for users your server has never seen before.
This commit is contained in:
Mark Felder 2024-07-25 11:18:27 -04:00
parent 700c106680
commit 1a482a73c3
3 changed files with 25 additions and 4 deletions

View file

@ -0,0 +1 @@
Fix Optimistic Inbox for failed signatures

View file

@ -293,8 +293,15 @@ def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
json(conn, "ok") json(conn, "ok")
end end
def inbox(%{assigns: %{valid_signature: false}, req_headers: req_headers} = conn, params) do def inbox(%{assigns: %{valid_signature: false}} = conn, params) do
Federator.incoming_ap_doc(%{req_headers: req_headers, params: params}) Federator.incoming_ap_doc(%{
method: conn.method,
req_headers: conn.req_headers,
request_path: conn.request_path,
params: params,
query_string: conn.query_string
})
json(conn, "ok") json(conn, "ok")
end end

View file

@ -12,13 +12,26 @@ defmodule Pleroma.Workers.ReceiverWorker do
@impl Oban.Worker @impl Oban.Worker
def perform(%Job{ def perform(%Job{
args: %{"op" => "incoming_ap_doc", "req_headers" => req_headers, "params" => params} args: %{
"op" => "incoming_ap_doc",
"method" => method,
"params" => params,
"req_headers" => req_headers,
"request_path" => request_path,
"query_string" => query_string
}
}) do }) do
# Oban's serialization converts our tuple headers to lists. # Oban's serialization converts our tuple headers to lists.
# Revert it for the signature validation. # Revert it for the signature validation.
req_headers = Enum.into(req_headers, [], &List.to_tuple(&1)) req_headers = Enum.into(req_headers, [], &List.to_tuple(&1))
conn_data = %{params: params, req_headers: req_headers} conn_data = %{
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"]), with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
{:ok, _public_key} <- Signature.refetch_public_key(conn_data), {:ok, _public_key} <- Signature.refetch_public_key(conn_data),