diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex index 40c612c83..f4ed9a6be 100644 --- a/lib/federation/activity_pub/transmogrifier.ex +++ b/lib/federation/activity_pub/transmogrifier.ex @@ -850,8 +850,8 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do # Handle incoming `Accept` activities wrapping a `Join` activity on an event defp do_handle_incoming_accept_join(join_object, %Actor{} = actor_accepting) do case get_participant(join_object, actor_accepting) do - {:ok, participant} -> - do_handle_incoming_accept_join_event(participant, actor_accepting) + {:ok, activity, participant} -> + do_handle_incoming_accept_join_event(participant, actor_accepting, activity) {:error, _err} -> case get_member(join_object) do @@ -870,17 +870,22 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do end end - defp do_handle_incoming_accept_join_event(%Participant{role: :participant}, _actor) do + defp do_handle_incoming_accept_join_event( + %Participant{role: :participant} = participant, + _actor, + activity + ) do Logger.debug( "Tried to handle an Accept activity on a Join activity with a event object but the participant is already validated" ) - nil + {:ok, activity, participant} end defp do_handle_incoming_accept_join_event( %Participant{role: role, event: event} = participant, - %Actor{} = actor_accepting + %Actor{} = actor_accepting, + _activity ) when role in [:not_approved, :rejected] do with %Event{} = event <- Events.get_event_with_preload!(event.id), @@ -932,7 +937,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do # Handle incoming `Reject` activities wrapping a `Join` activity on an event defp do_handle_incoming_reject_join(join_object, %Actor{} = actor_accepting) do - with {:join_event, {:ok, %Participant{event: event, role: role} = participant}} + with {:join_event, {:ok, _activity, %Participant{event: event, role: role} = participant}} when role != :rejected <- {:join_event, get_participant(join_object, actor_accepting)}, {:event, %Event{} = event} <- {:event, Events.get_event_with_preload!(event.id)}, @@ -943,7 +948,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do :ok <- Participation.send_emails_to_local_user(participant) do {:ok, activity, participant} else - {:join_event, {:ok, %Participant{role: :rejected}}} -> + {:join_event, {:ok, _activity, %Participant{role: :rejected}}} -> Logger.warn( "Tried to handle an Reject activity on a Join activity with a event object but the participant is already rejected" ) @@ -1040,18 +1045,18 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do end end - defp get_participant(join_object, %Actor{} = actor_accepting, loop \\ 1) do + defp get_participant(join_object, %Actor{} = actor_accepting, loop \\ 1, activity \\ nil) do with join_object_id when not is_nil(join_object_id) <- Utils.get_url(join_object), {:not_found, %Participant{} = participant} <- {:not_found, Events.get_participant_by_url(join_object_id)} do - {:ok, participant} + {:ok, activity, participant} else {:not_found, _err} -> with true <- is_map(join_object), true <- loop < 2, true <- Utils.are_same_origin?(actor_accepting.url, join_object["id"]), - {:ok, _activity, %Participant{url: participant_url}} <- handle_incoming(join_object) do - get_participant(participant_url, actor_accepting, 2) + {:ok, activity, %Participant{url: participant_url}} <- handle_incoming(join_object) do + get_participant(participant_url, actor_accepting, 2, activity) else _ -> {:error, "Participant URL not found"} diff --git a/test/federation/activity_pub/transmogrifier/accept_test.exs b/test/federation/activity_pub/transmogrifier/accept_test.exs new file mode 100644 index 000000000..41c80e2c8 --- /dev/null +++ b/test/federation/activity_pub/transmogrifier/accept_test.exs @@ -0,0 +1,73 @@ +defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.AcceptTest do + use Mobilizon.DataCase + + import Mox + alias Mobilizon.Federation.ActivityPub.Transmogrifier + alias Mobilizon.Service.HTTP.ActivityPub.Mock + + describe "Receiving an Accept Join Event activity from a foreign instance" do + @base_actor_data File.read!("test/fixtures/mastodon-actor.json") + |> Jason.decode!() + @actor_url "https://mobilizon.extinctionrebellion.fr/@anonymous" + @actor_data @base_actor_data + |> Map.put("id", @actor_url) + |> Map.put("preferredUsername", "anonymous") + + @osmi_actor_url "https://mobilizon.extinctionrebellion.fr/@osmi" + @osmi_actor_data @base_actor_data + |> Map.put("id", @osmi_actor_url) + |> Map.put("preferredUsername", "osmi") + + @xr_nantes_actor_url "https://mobilizon.extinctionrebellion.fr/@xr_nantes" + @xr_nantes_actor_data @base_actor_data + |> Map.put("id", @xr_nantes_actor_url) + |> Map.put("preferredUsername", "xr_nantes") + + @event_url "https://mobilizon.extinctionrebellion.fr/events/d70f8e0d-62dc-4897-a855-ebcbe9798fc1" + @event_data File.read!("test/fixtures/mobilizon-post-activity.json") + |> Jason.decode!() + |> Map.get("object") + |> Map.put("id", @event_url) + |> Map.put("actor", @osmi_actor_url) + |> Map.put("attributedTo", @xr_nantes_actor_url) + |> Map.put("tag", []) + + test "When the event is remote" do + object = %{ + "actor" => @actor_url, + "id" => + "https://mobilizon.extinctionrebellion.fr/join/event/b67cf172-af23-4ae8-b00e-a2e3643ccb21", + "object" => + "https://mobilizon.extinctionrebellion.fr/events/d70f8e0d-62dc-4897-a855-ebcbe9798fc1", + "participationMessage" => nil, + "published" => "2022-03-28T20:11:11Z", + "type" => "Join" + } + + activity = %{ + "type" => "Accept", + "object" => object, + "actor" => @actor_url, + "id" => + "https://mobilizon.extinctionrebellion.fr/join/event/b67cf172-af23-4ae8-b00e-a2e3643ccb21/activity" + } + + Mock + |> expect(:call, 4, fn + %{method: :get, url: @actor_url}, _opts -> + {:ok, %Tesla.Env{status: 200, body: @actor_data}} + + %{method: :get, url: @osmi_actor_url}, _opts -> + {:ok, %Tesla.Env{status: 200, body: @osmi_actor_data}} + + %{method: :get, url: @xr_nantes_actor_url}, _opts -> + {:ok, %Tesla.Env{status: 200, body: @xr_nantes_actor_data}} + + %{method: :get, url: @event_url}, _opts -> + {:ok, %Tesla.Env{status: 200, body: @event_data}} + end) + + assert {:ok, _activity, _object} = Transmogrifier.handle_incoming(activity) + end + end +end