From 20ff0a7f6cb4a3be9aabb0526852797cf50c1a92 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 26 Jul 2021 17:18:28 +0200 Subject: [PATCH] Refactor Mobilizon.Federation.ActivityPub.Permission to handle permissions Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/permission.ex | 54 +++++++++++++++---- lib/federation/activity_pub/types/actors.ex | 13 +++-- lib/federation/activity_pub/types/comments.ex | 12 +++-- .../activity_pub/types/discussions.ex | 8 +-- lib/federation/activity_pub/types/entity.ex | 47 +++++----------- lib/federation/activity_pub/types/events.ex | 15 +++--- lib/federation/activity_pub/types/posts.ex | 14 +++-- .../activity_pub/types/resources.ex | 7 +-- .../activity_pub/types/todo_lists.ex | 7 +-- lib/federation/activity_pub/types/todos.ex | 7 +-- .../activity_pub/types/tombstones.ex | 7 +-- 11 files changed, 110 insertions(+), 81 deletions(-) diff --git a/lib/federation/activity_pub/permission.ex b/lib/federation/activity_pub/permission.ex index e9d4377d..41a14afc 100644 --- a/lib/federation/activity_pub/permission.ex +++ b/lib/federation/activity_pub/permission.ex @@ -8,12 +8,42 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do alias Mobilizon.Federation.ActivityPub.Types.{Entity, Ownable} require Logger + use StructAccess + defstruct [:access, :create, :update, :delete] + + @member_roles [:member, :moderator, :administrator] + @doc """ Check that actor can access the object """ @spec can_access_group_object?(Actor.t(), Entity.t()) :: boolean() def can_access_group_object?(%Actor{} = actor, object) do - can_manage_group_object?(:role_needed_to_access, actor, object) + can_manage_group_object?(:access, actor, object) + end + + @doc """ + Check that actor can create such an object + """ + @spec can_create_group_object?(String.t() | integer(), String.t() | integer(), Entity.t()) :: + boolean() + def can_create_group_object?( + actor_id, + group_id, + object + ) do + case object |> Ownable.permissions() |> get_in([:create]) do + :member -> + Actors.is_member?(actor_id, group_id) + + :moderator -> + Actors.is_moderator?(actor_id, group_id) + + :administrator -> + Actors.is_administrator?(actor_id, group_id) + + _ -> + false + end end @doc """ @@ -21,7 +51,7 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do """ @spec can_update_group_object?(Actor.t(), Entity.t()) :: boolean() def can_update_group_object?(%Actor{} = actor, object) do - can_manage_group_object?(:role_needed_to_update, actor, object) + can_manage_group_object?(:update, actor, object) end @doc """ @@ -29,29 +59,31 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do """ @spec can_delete_group_object?(Actor.t(), Entity.t()) :: boolean() def can_delete_group_object?(%Actor{} = actor, object) do - can_manage_group_object?(:role_needed_to_delete, actor, object) + can_manage_group_object?(:delete, actor, object) end + @type existing_object_permissions :: :access | :update | :delete + @spec can_manage_group_object?( - :role_needed_to_access | :role_needed_to_update | :role_needed_to_delete, + existing_object_permissions(), Actor.t(), any() ) :: boolean() - defp can_manage_group_object?(action_function, %Actor{url: actor_url} = actor, object) do + defp can_manage_group_object?(permission, %Actor{url: actor_url} = actor, object) do if Ownable.group_actor(object) != nil do - case apply(Ownable, action_function, [object]) do - role when role in [:member, :moderator, :administrator] -> + case object |> Ownable.permissions() |> get_in([permission]) do + role when role in @member_roles -> activity_actor_is_group_member?(actor, object, role) _ -> - case action_function do - :role_needed_to_access -> + case permission do + :access -> Logger.warn("Actor #{actor_url} can't access #{object.url}") - :role_needed_to_update -> + :update -> Logger.warn("Actor #{actor_url} can't update #{object.url}") - :role_needed_to_delete -> + :delete -> Logger.warn("Actor #{actor_url} can't delete #{object.url}") end diff --git a/lib/federation/activity_pub/types/actors.ex b/lib/federation/activity_pub/types/actors.ex index 0d726771..3df8e275 100644 --- a/lib/federation/activity_pub/types/actors.ex +++ b/lib/federation/activity_pub/types/actors.ex @@ -3,7 +3,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do alias Mobilizon.Actors alias Mobilizon.Actors.{Actor, Follower, Member} alias Mobilizon.Federation.ActivityPub - alias Mobilizon.Federation.ActivityPub.{Audience, Relay} + alias Mobilizon.Federation.ActivityPub.{Audience, Permission, Relay} alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.GraphQL.API.Utils, as: APIUtils @@ -104,9 +104,14 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do def group_actor(%Actor{} = actor), do: actor - def role_needed_to_access(%Actor{} = _group), do: :member - def role_needed_to_update(%Actor{} = _group), do: :administrator - def role_needed_to_delete(%Actor{} = _group), do: :administrator + def permissions(%Actor{} = _group) do + %Permission{ + access: :member, + create: nil, + update: :administrator, + delete: :administrator + } + end @spec join(Actor.t(), Actor.t(), boolean(), map()) :: {:ok, map(), Member.t()} def join(%Actor{type: :Group} = group, %Actor{} = actor, _local, additional) do diff --git a/lib/federation/activity_pub/types/comments.ex b/lib/federation/activity_pub/types/comments.ex index 58f742f4..ea8de5ba 100644 --- a/lib/federation/activity_pub/types/comments.ex +++ b/lib/federation/activity_pub/types/comments.ex @@ -4,7 +4,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do alias Mobilizon.Actors.Actor alias Mobilizon.Discussions.{Comment, Discussion} alias Mobilizon.Events.{Event, EventOptions} - alias Mobilizon.Federation.ActivityPub.Audience + alias Mobilizon.Federation.ActivityPub.{Audience, Permission} alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils alias Mobilizon.Federation.ActivityStream.Convertible @@ -104,9 +104,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do def group_actor(_), do: nil - def role_needed_to_access(%Comment{}), do: :member - def role_needed_to_update(%Comment{attributed_to: %Actor{} = _group}), do: :administrator - def role_needed_to_delete(%Comment{attributed_to_id: _attributed_to_id}), do: :administrator + def permissions(%Comment{}), + do: %Permission{ + access: :member, + create: :member, + update: :administrator, + delete: :administrator + } # Prepare and sanitize arguments for comments defp prepare_args_for_comment(args) do diff --git a/lib/federation/activity_pub/types/discussions.ex b/lib/federation/activity_pub/types/discussions.ex index 3afc5859..f282a430 100644 --- a/lib/federation/activity_pub/types/discussions.ex +++ b/lib/federation/activity_pub/types/discussions.ex @@ -4,7 +4,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do alias Mobilizon.{Actors, Discussions} alias Mobilizon.Actors.Actor alias Mobilizon.Discussions.{Comment, Discussion} - alias Mobilizon.Federation.ActivityPub.Audience + alias Mobilizon.Federation.ActivityPub.{Audience, Permission} alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.GraphQL.API.Utils, as: APIUtils @@ -110,9 +110,9 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do def group_actor(%Discussion{actor_id: actor_id}), do: Actors.get_actor(actor_id) - def role_needed_to_access(%Discussion{}), do: :member - def role_needed_to_update(%Discussion{}), do: :moderator - def role_needed_to_delete(%Discussion{}), do: :moderator + def permissions(%Discussion{}) do + %Permission{access: :member, create: :member, update: :moderator, delete: :moderator} + end @spec maybe_publish_graphql_subscription(Discussion.t()) :: :ok defp maybe_publish_graphql_subscription(%Discussion{} = discussion) do diff --git a/lib/federation/activity_pub/types/entity.ex b/lib/federation/activity_pub/types/entity.ex index 2ba4831a..3500294a 100644 --- a/lib/federation/activity_pub/types/entity.ex +++ b/lib/federation/activity_pub/types/entity.ex @@ -17,6 +17,7 @@ alias Mobilizon.Federation.ActivityPub.Types.{ alias Mobilizon.Actors.{Actor, Member} alias Mobilizon.Events.Event alias Mobilizon.Discussions.{Comment, Discussion} +alias Mobilizon.Federation.ActivityPub.Permission alias Mobilizon.Posts.Post alias Mobilizon.Resources.Resource alias Mobilizon.Todos.{Todo, TodoList} @@ -67,14 +68,8 @@ defprotocol Mobilizon.Federation.ActivityPub.Types.Ownable do @doc "Returns the actor for the entity" def actor(entity) - @spec role_needed_to_access(Entity.t()) :: group_role() - def role_needed_to_access(entity) - - @spec role_needed_to_update(Entity.t()) :: group_role() - def role_needed_to_update(entity) - - @spec role_needed_to_delete(Entity.t()) :: group_role() - def role_needed_to_delete(entity) + @spec permissions(Entity.t()) :: Permission.t() + def permissions(entity) end defimpl Managable, for: Event do @@ -85,9 +80,7 @@ end defimpl Ownable, for: Event do defdelegate group_actor(entity), to: Events defdelegate actor(entity), to: Events - defdelegate role_needed_to_access(entity), to: Events - defdelegate role_needed_to_update(entity), to: Events - defdelegate role_needed_to_delete(entity), to: Events + defdelegate permissions(entity), to: Events end defimpl Managable, for: Comment do @@ -98,9 +91,7 @@ end defimpl Ownable, for: Comment do defdelegate group_actor(entity), to: Comments defdelegate actor(entity), to: Comments - defdelegate role_needed_to_access(entity), to: Comments - defdelegate role_needed_to_update(entity), to: Comments - defdelegate role_needed_to_delete(entity), to: Comments + defdelegate permissions(entity), to: Comments end defimpl Managable, for: Post do @@ -111,9 +102,7 @@ end defimpl Ownable, for: Post do defdelegate group_actor(entity), to: Posts defdelegate actor(entity), to: Posts - defdelegate role_needed_to_access(entity), to: Posts - defdelegate role_needed_to_update(entity), to: Posts - defdelegate role_needed_to_delete(entity), to: Posts + defdelegate permissions(entity), to: Posts end defimpl Managable, for: Actor do @@ -124,9 +113,7 @@ end defimpl Ownable, for: Actor do defdelegate group_actor(entity), to: Actors defdelegate actor(entity), to: Actors - defdelegate role_needed_to_access(entity), to: Actors - defdelegate role_needed_to_update(entity), to: Actors - defdelegate role_needed_to_delete(entity), to: Actors + defdelegate permissions(entity), to: Actors end defimpl Managable, for: TodoList do @@ -137,9 +124,7 @@ end defimpl Ownable, for: TodoList do defdelegate group_actor(entity), to: TodoLists defdelegate actor(entity), to: TodoLists - defdelegate role_needed_to_access(entity), to: TodoLists - defdelegate role_needed_to_update(entity), to: TodoLists - defdelegate role_needed_to_delete(entity), to: TodoLists + defdelegate permissions(entity), to: TodoLists end defimpl Managable, for: Todo do @@ -150,9 +135,7 @@ end defimpl Ownable, for: Todo do defdelegate group_actor(entity), to: Todos defdelegate actor(entity), to: Todos - defdelegate role_needed_to_access(entity), to: Todos - defdelegate role_needed_to_update(entity), to: Todos - defdelegate role_needed_to_delete(entity), to: Todos + defdelegate permissions(entity), to: Todos end defimpl Managable, for: Resource do @@ -163,9 +146,7 @@ end defimpl Ownable, for: Resource do defdelegate group_actor(entity), to: Resources defdelegate actor(entity), to: Resources - defdelegate role_needed_to_access(entity), to: Resources - defdelegate role_needed_to_update(entity), to: Resources - defdelegate role_needed_to_delete(entity), to: Resources + defdelegate permissions(entity), to: Resources end defimpl Managable, for: Discussion do @@ -176,17 +157,13 @@ end defimpl Ownable, for: Discussion do defdelegate group_actor(entity), to: Discussions defdelegate actor(entity), to: Discussions - defdelegate role_needed_to_access(entity), to: Discussions - defdelegate role_needed_to_update(entity), to: Discussions - defdelegate role_needed_to_delete(entity), to: Discussions + defdelegate permissions(entity), to: Discussions end defimpl Ownable, for: Tombstone do defdelegate group_actor(entity), to: Tombstones defdelegate actor(entity), to: Tombstones - defdelegate role_needed_to_access(entity), to: Tombstones - defdelegate role_needed_to_update(entity), to: Tombstones - defdelegate role_needed_to_delete(entity), to: Tombstones + defdelegate permissions(entity), to: Tombstones end defimpl Managable, for: Member do diff --git a/lib/federation/activity_pub/types/events.ex b/lib/federation/activity_pub/types/events.ex index 4a334a94..917c0769 100644 --- a/lib/federation/activity_pub/types/events.ex +++ b/lib/federation/activity_pub/types/events.ex @@ -5,7 +5,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do alias Mobilizon.Events, as: EventsManager alias Mobilizon.Events.{Event, Participant} alias Mobilizon.Federation.ActivityPub - alias Mobilizon.Federation.ActivityPub.Audience + alias Mobilizon.Federation.ActivityPub.{Audience, Permission} alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils alias Mobilizon.Federation.ActivityStream.Convertible @@ -95,11 +95,14 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do def group_actor(_), do: nil - def role_needed_to_access(%Event{draft: false}), do: :member - def role_needed_to_access(%Event{}), do: :moderator - def role_needed_to_update(%Event{attributed_to: %Actor{} = _group}), do: :moderator - def role_needed_to_delete(%Event{attributed_to_id: _attributed_to_id}), do: :moderator - def role_needed_to_delete(_), do: nil + def permissions(%Event{draft: draft, attributed_to_id: _attributed_to_id}) do + %Permission{ + access: if(draft, do: nil, else: :member), + create: :moderator, + update: :moderator, + delete: :moderator + } + end def join(%Event{} = event, %Actor{} = actor, _local, additional) do with {:maximum_attendee_capacity, true} <- diff --git a/lib/federation/activity_pub/types/posts.ex b/lib/federation/activity_pub/types/posts.ex index a507d768..fb3f4f87 100644 --- a/lib/federation/activity_pub/types/posts.ex +++ b/lib/federation/activity_pub/types/posts.ex @@ -2,7 +2,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do @moduledoc false alias Mobilizon.{Actors, Posts, Tombstone} alias Mobilizon.Actors.Actor - alias Mobilizon.Federation.ActivityPub.Audience + alias Mobilizon.Federation.ActivityPub.{Audience, Permission} alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils alias Mobilizon.Federation.ActivityStream.Convertible @@ -91,8 +91,12 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do def group_actor(%Post{attributed_to_id: attributed_to_id}), do: Actors.get_actor(attributed_to_id) - def role_needed_to_access(%Post{draft: false}), do: :member - def role_needed_to_access(%Post{}), do: :moderator - def role_needed_to_update(%Post{}), do: :moderator - def role_needed_to_delete(%Post{}), do: :moderator + def permissions(%Post{draft: draft}) do + %Permission{ + access: if(draft, do: nil, else: :member), + create: :moderator, + update: :moderator, + delete: :moderator + } + end end diff --git a/lib/federation/activity_pub/types/resources.ex b/lib/federation/activity_pub/types/resources.ex index 66b65e59..38f3b409 100644 --- a/lib/federation/activity_pub/types/resources.ex +++ b/lib/federation/activity_pub/types/resources.ex @@ -2,6 +2,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do @moduledoc false alias Mobilizon.{Actors, Resources} alias Mobilizon.Actors.Actor + alias Mobilizon.Federation.ActivityPub.Permission alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.Resources.Resource @@ -170,7 +171,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do def group_actor(%Resource{actor_id: actor_id}), do: Actors.get_actor(actor_id) - def role_needed_to_access(%Resource{}), do: :member - def role_needed_to_update(%Resource{}), do: :member - def role_needed_to_delete(%Resource{}), do: :member + def permissions(%Resource{}) do + %Permission{access: :member, create: :member, update: :member, delete: :member} + end end diff --git a/lib/federation/activity_pub/types/todo_lists.ex b/lib/federation/activity_pub/types/todo_lists.ex index 58eb7999..fcabf102 100644 --- a/lib/federation/activity_pub/types/todo_lists.ex +++ b/lib/federation/activity_pub/types/todo_lists.ex @@ -2,6 +2,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.TodoLists do @moduledoc false alias Mobilizon.{Actors, Todos} alias Mobilizon.Actors.Actor + alias Mobilizon.Federation.ActivityPub.Permission alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream alias Mobilizon.Federation.ActivityStream.Convertible @@ -68,7 +69,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.TodoLists do def group_actor(%TodoList{actor_id: actor_id}), do: Actors.get_actor(actor_id) - def role_needed_to_access(%TodoList{}), do: :member - def role_needed_to_update(%TodoList{}), do: :member - def role_needed_to_delete(%TodoList{}), do: :member + def permissions(%TodoList{}) do + %Permission{access: :member, create: :member, update: :member, delete: :member} + end end diff --git a/lib/federation/activity_pub/types/todos.ex b/lib/federation/activity_pub/types/todos.ex index bae75478..b12463ce 100644 --- a/lib/federation/activity_pub/types/todos.ex +++ b/lib/federation/activity_pub/types/todos.ex @@ -2,6 +2,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do @moduledoc false alias Mobilizon.{Actors, Todos} alias Mobilizon.Actors.Actor + alias Mobilizon.Federation.ActivityPub.Permission alias Mobilizon.Federation.ActivityPub.Types.Entity alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.Todos.{Todo, TodoList} @@ -80,7 +81,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do end end - def role_needed_to_access(%Todo{}), do: :member - def role_needed_to_update(%Todo{}), do: :member - def role_needed_to_delete(%Todo{}), do: :member + def permissions(%Todo{}) do + %Permission{access: :member, create: :member, update: :member, delete: :member} + end end diff --git a/lib/federation/activity_pub/types/tombstones.ex b/lib/federation/activity_pub/types/tombstones.ex index 5586a005..9535d08e 100644 --- a/lib/federation/activity_pub/types/tombstones.ex +++ b/lib/federation/activity_pub/types/tombstones.ex @@ -2,6 +2,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Tombstones do @moduledoc false alias Mobilizon.{Actors, Tombstone} alias Mobilizon.Actors.Actor + alias Mobilizon.Federation.ActivityPub.Permission def actor(%Tombstone{actor: %Actor{id: actor_id}}), do: Actors.get_actor(actor_id) @@ -12,7 +13,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Tombstones do def group_actor(_), do: nil - def role_needed_to_access(%Actor{}), do: nil - def role_needed_to_update(%Actor{}), do: nil - def role_needed_to_delete(%Actor{}), do: nil + def permissions(_) do + %Permission{access: nil, create: nil, update: nil, delete: nil} + end end