Refactor Mobilizon.Federation.ActivityPub.Permission to handle

permissions

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2021-07-26 17:18:28 +02:00
parent 1ceb976f4e
commit 20ff0a7f6c
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
11 changed files with 110 additions and 81 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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} <-

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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