From e05735265b16e0ab9d40a6565b67a56660668fc0 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 13 Aug 2021 11:22:04 +0200 Subject: [PATCH] Fix remote group moderators managing event participations Closes #827 Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/transmogrifier.ex | 14 ++++---- lib/graphql/api/participations.ex | 1 + lib/graphql/resolvers/event.ex | 36 ++++--------------- lib/graphql/resolvers/event/utils.ex | 34 ++++++++++++++++++ lib/graphql/resolvers/participant.ex | 13 +++---- 5 files changed, 55 insertions(+), 43 deletions(-) create mode 100644 lib/graphql/resolvers/event/utils.ex diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex index e7c06ce12..0ebd70a04 100644 --- a/lib/federation/activity_pub/transmogrifier.ex +++ b/lib/federation/activity_pub/transmogrifier.ex @@ -870,7 +870,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do when role in [:not_approved, :rejected] do with %Event{} = event <- Events.get_event_with_preload!(event.id), {:can_accept_event_join, true} <- - {:can_accept_event_join, can_accept_event_join?(actor_accepting, event)}, + {:can_accept_event_join, can_manage_event?(actor_accepting, event)}, {:ok, %Activity{} = activity, %Participant{role: :participant} = participant} <- ActivityPub.accept( :join, @@ -918,9 +918,9 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do with {:join_event, {:ok, %Participant{event: event, role: role} = participant}} when role != :rejected <- {:join_event, get_participant(join_object, actor_accepting)}, - # TODO: The actor that accepts the Join activity may another one that the event organizer ? - # Or maybe for groups it's the group that sends the Accept activity - {:same_actor, true} <- {:same_actor, actor_accepting.id == event.organizer_actor_id}, + {:event, %Event{} = event} <- {:event, Events.get_event_with_preload!(event.id)}, + {:can_accept_event_reject, true} <- + {:can_accept_event_reject, can_manage_event?(actor_accepting, event)}, {:ok, activity, participant} <- ActivityPub.reject(:join, participant, false), :ok <- Participation.send_emails_to_local_user(participant) do @@ -1142,21 +1142,21 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do end end - defp can_accept_event_join?( + defp can_manage_event?( %Actor{url: actor_url} = actor, %Event{attributed_to: %Actor{type: :Group, url: group_url} = _group} = event ) do actor_url == group_url || Permission.can_update_group_object?(actor, event) end - defp can_accept_event_join?( + defp can_manage_event?( %Actor{id: actor_id}, %Event{organizer_actor: %Actor{id: organizer_actor_id}} ) do organizer_actor_id == actor_id end - defp can_accept_event_join?(_actor, _event) do + defp can_manage_event?(_actor, _event) do false end end diff --git a/lib/graphql/api/participations.ex b/lib/graphql/api/participations.ex index 8d89c7b52..55ce95c11 100644 --- a/lib/graphql/api/participations.ex +++ b/lib/graphql/api/participations.ex @@ -75,6 +75,7 @@ defmodule Mobilizon.GraphQL.API.Participations do ActivityPub.reject( :join, participation, + true, %{"actor" => moderator.url} ), :ok <- Participation.send_emails_to_local_user(participation) do diff --git a/lib/graphql/resolvers/event.ex b/lib/graphql/resolvers/event.ex index 5cebe5e13..318bd75ed 100644 --- a/lib/graphql/resolvers/event.ex +++ b/lib/graphql/resolvers/event.ex @@ -15,6 +15,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do alias Mobilizon.Federation.ActivityPub.Permission import Mobilizon.Users.Guards, only: [is_moderator: 1] import Mobilizon.Web.Gettext + import Mobilizon.GraphQL.Resolvers.Event.Utils # We limit the max number of events that can be retrieved @event_max_limit 100 @@ -133,14 +134,14 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do List participants for event (through an event request) """ def list_participants_for_event( - %Event{id: event_id}, + %Event{id: event_id} = event, %{page: page, limit: limit, roles: roles}, %{context: %{current_user: %User{} = user}} = _resolution ) do - with %Actor{id: actor_id} <- Users.get_actor_for_user(user), + with %Actor{} = actor <- Users.get_actor_for_user(user), # Check that moderator has right - {:actor_approve_permission, true} <- - {:actor_approve_permission, Events.moderator_for_event?(event_id, actor_id)} do + {:event_can_be_managed, true} <- + {:event_can_be_managed, can_event_be_updated_by?(event, actor)} do roles = case roles do nil -> @@ -159,7 +160,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do participants = Events.list_participants_for_event(event_id, roles, page, limit) {:ok, participants} else - {:actor_approve_permission, _} -> + {:event_can_be_managed, _} -> {:error, dgettext("errors", "Provided profile doesn't have moderator permissions on this event")} end @@ -414,29 +415,4 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do {:ok, args} end end - - defp can_event_be_updated_by?( - %Event{attributed_to: %Actor{type: :Group}} = event, - %Actor{} = actor_member - ) do - Permission.can_update_group_object?(actor_member, event) - end - - defp can_event_be_updated_by?( - %Event{} = event, - %Actor{id: actor_member_id} - ) do - Event.can_be_managed_by?(event, actor_member_id) - end - - defp can_event_be_deleted_by?( - %Event{attributed_to: %Actor{type: :Group}} = event, - %Actor{} = actor_member - ) do - Permission.can_delete_group_object?(actor_member, event) - end - - defp can_event_be_deleted_by?(%Event{} = event, %Actor{id: actor_member_id}) do - Event.can_be_managed_by?(event, actor_member_id) - end end diff --git a/lib/graphql/resolvers/event/utils.ex b/lib/graphql/resolvers/event/utils.ex new file mode 100644 index 000000000..e6c7e8c24 --- /dev/null +++ b/lib/graphql/resolvers/event/utils.ex @@ -0,0 +1,34 @@ +defmodule Mobilizon.GraphQL.Resolvers.Event.Utils do + @moduledoc """ + Tools to test permission on events + """ + + alias Mobilizon.Actors.Actor + alias Mobilizon.Events.Event + alias Mobilizon.Federation.ActivityPub.Permission + + def can_event_be_updated_by?( + %Event{attributed_to: %Actor{type: :Group}} = event, + %Actor{} = actor_member + ) do + Permission.can_update_group_object?(actor_member, event) + end + + def can_event_be_updated_by?( + %Event{} = event, + %Actor{id: actor_member_id} + ) do + Event.can_be_managed_by?(event, actor_member_id) + end + + def can_event_be_deleted_by?( + %Event{attributed_to: %Actor{type: :Group}} = event, + %Actor{} = actor_member + ) do + Permission.can_delete_group_object?(actor_member, event) + end + + def can_event_be_deleted_by?(%Event{} = event, %Actor{id: actor_member_id}) do + Event.can_be_managed_by?(event, actor_member_id) + end +end diff --git a/lib/graphql/resolvers/participant.ex b/lib/graphql/resolvers/participant.ex index d09259eb4..9c41217fb 100644 --- a/lib/graphql/resolvers/participant.ex +++ b/lib/graphql/resolvers/participant.ex @@ -11,6 +11,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do alias Mobilizon.Web.Email.Checker require Logger import Mobilizon.Web.Gettext + import Mobilizon.GraphQL.Resolvers.Event.Utils @doc """ Join an event for an regular or anonymous actor @@ -213,15 +214,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do } ) do # Check that moderator provided is rightly authenticated - with %Actor{id: moderator_actor_id} = moderator_actor <- Users.get_actor_for_user(user), + with %Actor{} = moderator_actor <- Users.get_actor_for_user(user), # Check that participation already exists - {:has_participation, %Participant{role: old_role} = participation} <- + {:has_participation, %Participant{role: old_role, event_id: event_id} = participation} <- {:has_participation, Events.get_participant(participation_id)}, {:same_role, false} <- {:same_role, new_role == old_role}, # Check that moderator has right - {:actor_approve_permission, true} <- - {:actor_approve_permission, - Events.moderator_for_event?(participation.event.id, moderator_actor_id)}, + {:event, %Event{} = event} <- {:event, Events.get_event_with_preload!(event_id)}, + {:event_can_be_managed, true} <- + {:event_can_be_managed, can_event_be_updated_by?(event, moderator_actor)}, {:ok, _activity, participation} <- Participations.update(participation, moderator_actor, new_role) do {:ok, participation} @@ -229,7 +230,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do {:has_participation, nil} -> {:error, dgettext("errors", "Participant not found")} - {:actor_approve_permission, _} -> + {:event_can_be_managed, _} -> {:error, dgettext("errors", "Provided profile doesn't have moderator permissions on this event")}