Various typespec and compilation improvements
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -41,7 +41,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
|
||||
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
||||
|
||||
alias Mobilizon.Federation.ActivityPub.Types.{Managable, Ownable}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.{Entity, Managable, Ownable}
|
||||
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Federation.HTTPSignatures.Signature
|
||||
@@ -56,11 +56,9 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
|
||||
@public_ap_adress "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
@doc """
|
||||
Wraps an object into an activity
|
||||
"""
|
||||
# Wraps an object into an activity
|
||||
@spec create_activity(map(), boolean()) :: {:ok, Activity.t()}
|
||||
def create_activity(map, local \\ true) when is_map(map) do
|
||||
defp create_activity(map, local) when is_map(map) do
|
||||
with map <- lazy_put_activity_defaults(map) do
|
||||
{:ok,
|
||||
%Activity{
|
||||
@@ -168,7 +166,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
* Federates (asynchronously) the activity
|
||||
* Returns the activity
|
||||
"""
|
||||
@spec create(atom(), map(), boolean, map()) :: {:ok, Activity.t(), struct()} | any()
|
||||
@spec create(atom(), map(), boolean, map()) :: {:ok, Activity.t(), Entity.entities()} | any()
|
||||
def create(type, args, local \\ false, additional \\ %{}) do
|
||||
Logger.debug("creating an activity")
|
||||
Logger.debug(inspect(args))
|
||||
@@ -206,7 +204,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
* Federates (asynchronously) the activity
|
||||
* Returns the activity
|
||||
"""
|
||||
@spec update(struct(), map(), boolean, map()) :: {:ok, Activity.t(), struct()} | any()
|
||||
@spec update(Entity.entities(), map(), boolean, map()) ::
|
||||
{:ok, Activity.t(), Entity.entities()} | any()
|
||||
def update(old_entity, args, local \\ false, additional \\ %{}) do
|
||||
Logger.debug("updating an activity")
|
||||
Logger.debug(inspect(args))
|
||||
@@ -224,6 +223,12 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@type acceptable_types :: :join | :follow | :invite
|
||||
@type acceptable_entities ::
|
||||
accept_join_entities | accept_follow_entities | accept_invite_entities
|
||||
|
||||
@spec accept(acceptable_types, acceptable_entities, boolean, map) ::
|
||||
{:ok, ActivityStream.t(), acceptable_entities}
|
||||
def accept(type, entity, local \\ true, additional \\ %{}) do
|
||||
Logger.debug("We're accepting something")
|
||||
|
||||
@@ -246,6 +251,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec reject(acceptable_types, acceptable_entities, boolean, map) ::
|
||||
{:ok, ActivityStream.t(), acceptable_entities}
|
||||
def reject(type, entity, local \\ true, additional \\ %{}) do
|
||||
{:ok, entity, update_data} =
|
||||
case type do
|
||||
@@ -266,6 +273,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec announce(Actor.t(), ActivityStream.t(), String.t() | nil, boolean, boolean) ::
|
||||
{:ok, Activity.t(), ActivityStream.t()}
|
||||
def announce(
|
||||
%Actor{} = actor,
|
||||
object,
|
||||
@@ -286,6 +295,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec unannounce(Actor.t(), ActivityStream.t(), String.t() | nil, String.t() | nil, boolean) ::
|
||||
{:ok, Activity.t(), ActivityStream.t()}
|
||||
def unannounce(
|
||||
%Actor{} = actor,
|
||||
object,
|
||||
@@ -306,6 +317,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
@doc """
|
||||
Make an actor follow another
|
||||
"""
|
||||
@spec follow(Actor.t(), Actor.t(), String.t() | nil, boolean, map) ::
|
||||
{:ok, Activity.t(), Follower.t()} | {:error, String.t()}
|
||||
def follow(
|
||||
%Actor{} = follower,
|
||||
%Actor{} = followed,
|
||||
@@ -336,7 +349,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
@doc """
|
||||
Make an actor unfollow another
|
||||
"""
|
||||
@spec unfollow(Actor.t(), Actor.t(), String.t(), boolean()) :: {:ok, map()} | any()
|
||||
@spec unfollow(Actor.t(), Actor.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t(), Follower.t()}
|
||||
def unfollow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, %Follower{id: follow_id} = follow} <- Actors.unfollow(followed, follower),
|
||||
# We recreate the follow activity
|
||||
@@ -357,6 +371,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec delete(Entity.t(), Actor.t(), boolean, map) :: {:ok, Activity.t(), Entity.t()}
|
||||
def delete(object, actor, local \\ true, additional \\ %{}) do
|
||||
with {:ok, activity_data, actor, object} <-
|
||||
Managable.delete(object, actor, local, additional),
|
||||
@@ -369,6 +384,9 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec join(Event.t(), Actor.t(), boolean, map) ::
|
||||
{:ok, Activity.t(), Participant.t()} | {:maximum_attendee_capacity, any}
|
||||
@spec join(Actor.t(), Actor.t(), boolean, map) :: {:ok, Activity.t(), Member.t()}
|
||||
def join(entity_to_join, actor_joining, local \\ true, additional \\ %{})
|
||||
|
||||
def join(%Event{} = event, %Actor{} = actor, local, additional) do
|
||||
@@ -397,6 +415,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec leave(Event.t(), Actor.t(), boolean, map) :: {:ok, Activity.t(), Participant.t()}
|
||||
@spec leave(Actor.t(), Actor.t(), boolean, map) :: {:ok, Activity.t(), Member.t()}
|
||||
def leave(object, actor, local \\ true, additional \\ %{})
|
||||
|
||||
@doc """
|
||||
@@ -462,6 +482,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec remove(Member.t(), Actor.t(), Actor.t(), boolean, map) :: {:ok, Activity.t(), Member.t()}
|
||||
def remove(
|
||||
%Member{} = member,
|
||||
%Actor{type: :Group, url: group_url, members_url: group_members_url},
|
||||
@@ -502,7 +523,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
) do
|
||||
Logger.debug("Handling #{actor_url} invite to #{group_url} sent to #{target_actor_url}")
|
||||
|
||||
with {:is_able_to_invite, true} <- {:is_able_to_invite, is_able_to_invite(actor, group)},
|
||||
with {:is_able_to_invite, true} <- {:is_able_to_invite, is_able_to_invite?(actor, group)},
|
||||
{:ok, %Member{url: member_url} = member} <-
|
||||
Actors.create_member(%{
|
||||
parent_id: group_id,
|
||||
@@ -538,7 +559,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
defp is_able_to_invite(%Actor{domain: actor_domain, id: actor_id}, %Actor{
|
||||
@spec is_able_to_invite?(Actor.t(), Actor.t()) :: boolean
|
||||
defp is_able_to_invite?(%Actor{domain: actor_domain, id: actor_id}, %Actor{
|
||||
domain: group_domain,
|
||||
id: group_id
|
||||
}) do
|
||||
@@ -547,12 +569,17 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
true
|
||||
else
|
||||
# If local group, we'll send the invite
|
||||
with {:ok, %Member{} = admin_member} <- Actors.get_member(actor_id, group_id) do
|
||||
Member.is_administrator(admin_member)
|
||||
case Actors.get_member(actor_id, group_id) do
|
||||
{:ok, %Member{} = admin_member} ->
|
||||
Member.is_administrator(admin_member)
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec move(:resource, Resource.t(), map, boolean, map) :: {:ok, Activity.t(), Resource.t()}
|
||||
def move(type, old_entity, args, local \\ false, additional \\ %{}) do
|
||||
Logger.debug("We're moving something")
|
||||
Logger.debug(inspect(args))
|
||||
@@ -572,6 +599,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec flag(map, boolean, map) :: {:ok, Activity.t(), Report.t()}
|
||||
def flag(args, local \\ false, additional \\ %{}) do
|
||||
with {report, report_as_data} <- Types.Reports.flag(args, local, additional),
|
||||
{:ok, activity} <- create_activity(report_as_data, local),
|
||||
@@ -615,6 +643,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end)
|
||||
end
|
||||
|
||||
@spec convert_followers_in_recipients(list(String.t())) :: {list(String.t()), list(String.t())}
|
||||
defp convert_followers_in_recipients(recipients) do
|
||||
Enum.reduce(recipients, {recipients, []}, fn recipient, {recipients, follower_actors} = acc ->
|
||||
case Actors.get_actor_by_followers_url(recipient) do
|
||||
@@ -678,6 +707,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
@doc """
|
||||
Publish an activity to a specific inbox
|
||||
"""
|
||||
@spec publish_one(%{inbox: String.t(), json: String.t(), actor: Actor.t(), id: String.t()}) ::
|
||||
Tesla.Env.result()
|
||||
def publish_one(%{inbox: inbox, json: json, actor: actor, id: id}) do
|
||||
Logger.info("Federating #{id} to #{inbox}")
|
||||
%URI{host: host, path: path} = URI.parse(inbox)
|
||||
@@ -711,7 +742,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
@doc """
|
||||
Return all public activities (events & comments) for an actor
|
||||
"""
|
||||
@spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: map()
|
||||
@spec fetch_public_activities_for_actor(Actor.t(), pos_integer(), pos_integer()) :: map()
|
||||
def fetch_public_activities_for_actor(%Actor{id: actor_id} = actor, page \\ 1, limit \\ 10) do
|
||||
%Actor{id: relay_actor_id} = Relay.get_actor()
|
||||
|
||||
@@ -769,6 +800,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
defp check_for_tombstones(%{url: url}), do: Tombstone.find_tombstone(url)
|
||||
defp check_for_tombstones(_), do: nil
|
||||
|
||||
@typep accept_follow_entities :: Follower.t()
|
||||
|
||||
@spec accept_follow(Follower.t(), map) :: {:ok, Follower.t(), Activity.t()} | any
|
||||
defp accept_follow(%Follower{} = follower, additional) do
|
||||
with {:ok, %Follower{} = follower} <- Actors.update_follower(follower, %{approved: true}),
|
||||
@@ -792,7 +825,10 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec accept_join(Participant.t(), map) :: {:ok, Participant.t(), Activity.t()} | any
|
||||
@typep accept_join_entities :: Participant.t() | Member.t()
|
||||
|
||||
@spec accept_join(Participant.t(), map) :: {:ok, Participant.t(), Activity.t()}
|
||||
@spec accept_join(Member.t(), map) :: {:ok, Member.t(), Activity.t()}
|
||||
defp accept_join(%Participant{} = participant, additional) do
|
||||
with {:ok, %Participant{} = participant} <-
|
||||
Events.update_participant(participant, %{role: :participant}),
|
||||
@@ -820,7 +856,6 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec accept_join(Member.t(), map) :: {:ok, Member.t(), Activity.t()} | any
|
||||
defp accept_join(%Member{} = member, additional) do
|
||||
with {:ok, %Member{} = member} <-
|
||||
Actors.update_member(member, %{role: :member}),
|
||||
@@ -854,6 +889,8 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@typep accept_invite_entities :: Member.t()
|
||||
|
||||
@spec accept_invite(Member.t(), map()) :: {:ok, Member.t(), Activity.t()} | any
|
||||
defp accept_invite(
|
||||
%Member{invited_by_id: invited_by_id, actor_id: actor_id} = member,
|
||||
@@ -881,6 +918,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
@spec maybe_refresh_group(Member.t()) :: :ok | nil
|
||||
defp maybe_refresh_group(%Member{
|
||||
parent: %Actor{domain: parent_domain, url: parent_url},
|
||||
actor: %Actor{} = actor
|
||||
|
||||
@@ -108,7 +108,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
|
||||
{:ok, url} when is_binary(url) ->
|
||||
make_actor_from_url(url, preload)
|
||||
|
||||
_e ->
|
||||
{:error, _e} ->
|
||||
{:error, "No ActivityPub URL found in WebFinger"}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -99,6 +99,8 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
|
||||
}
|
||||
end
|
||||
|
||||
@spec get_to_and_cc(Actor.t(), list(), :direct | :private | :public | :unlisted | {:list, any}) ::
|
||||
{list(), list()}
|
||||
@doc """
|
||||
Determines the full audience based on mentions for an audience
|
||||
|
||||
@@ -118,7 +120,6 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
|
||||
* `to` : the mentioned actors and the eventual actor we're replying to
|
||||
* `cc` : none
|
||||
"""
|
||||
@spec get_to_and_cc(Actor.t(), list(), String.t()) :: {list(), list()}
|
||||
def get_to_and_cc(%Actor{} = actor, mentions, :public) do
|
||||
to = [@ap_public | mentions]
|
||||
cc = [actor.followers_url]
|
||||
@@ -128,7 +129,6 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
|
||||
{to, cc}
|
||||
end
|
||||
|
||||
@spec get_to_and_cc(Actor.t(), list(), String.t()) :: {list(), list()}
|
||||
def get_to_and_cc(%Actor{} = actor, mentions, :unlisted) do
|
||||
to = [actor.followers_url | mentions]
|
||||
cc = [@ap_public]
|
||||
@@ -138,7 +138,6 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
|
||||
{to, cc}
|
||||
end
|
||||
|
||||
@spec get_to_and_cc(Actor.t(), list(), String.t()) :: {list(), list()}
|
||||
def get_to_and_cc(%Actor{} = actor, mentions, :private) do
|
||||
{to, cc} = get_to_and_cc(actor, mentions, :direct)
|
||||
|
||||
@@ -147,7 +146,6 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
|
||||
{to, cc}
|
||||
end
|
||||
|
||||
@spec get_to_and_cc(Actor.t(), list(), String.t()) :: {list(), list()}
|
||||
def get_to_and_cc(_actor, mentions, :direct) do
|
||||
{mentions, []}
|
||||
end
|
||||
|
||||
@@ -13,6 +13,8 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do
|
||||
|
||||
@member_roles [:member, :moderator, :administrator]
|
||||
|
||||
@type object :: %{id: String.t(), url: String.t()}
|
||||
|
||||
@doc """
|
||||
Check that actor can access the object
|
||||
"""
|
||||
@@ -66,8 +68,8 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do
|
||||
|
||||
@spec can_manage_group_object?(
|
||||
existing_object_permissions(),
|
||||
Actor.t(),
|
||||
any()
|
||||
%Actor{url: String.t()},
|
||||
object()
|
||||
) :: boolean()
|
||||
defp can_manage_group_object?(permission, %Actor{url: actor_url} = actor, object) do
|
||||
if Ownable.group_actor(object) != nil do
|
||||
@@ -94,7 +96,7 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do
|
||||
end
|
||||
end
|
||||
|
||||
@spec activity_actor_is_group_member?(Actor.t(), Entity.t(), atom()) :: boolean()
|
||||
@spec activity_actor_is_group_member?(Actor.t(), object(), atom()) :: boolean()
|
||||
defp activity_actor_is_group_member?(
|
||||
%Actor{id: actor_id, url: actor_url},
|
||||
object,
|
||||
|
||||
@@ -951,7 +951,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||
defp do_handle_incoming_reject_invite(invite_object, %Actor{} = actor_rejecting) do
|
||||
with {:invite, {:ok, %Member{role: :invited, actor_id: actor_id} = member}} <-
|
||||
{:invite, get_member(invite_object)},
|
||||
{:same_actor, true} <- {:same_actor, actor_rejecting.id === actor_id},
|
||||
{:same_actor, true} <- {:same_actor, actor_rejecting.id == actor_id},
|
||||
{:ok, activity, member} <-
|
||||
ActivityPub.reject(:invite, member, false) do
|
||||
{:ok, activity, member}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
@moduledoc false
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.{Actor, Follower, Member}
|
||||
alias Mobilizon.Actors.{Actor, Follower, Member, MemberRole}
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Federation.ActivityPub.{Audience, Permission, Relay}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.GraphQL.API.Utils, as: APIUtils
|
||||
alias Mobilizon.Service.Activity.Group, as: GroupActivity
|
||||
@@ -17,7 +18,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Actor.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with args <- prepare_args_for_actor(args),
|
||||
{:ok, %Actor{} = actor} <- Actors.create_actor(args),
|
||||
@@ -35,7 +36,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Actor.t(), map, map) :: {:ok, Actor.t(), Activity.t()} | any
|
||||
@spec update(Actor.t(), map, map) :: {:ok, Actor.t(), ActivityStream.t()}
|
||||
def update(%Actor{} = old_actor, args, additional) do
|
||||
with {:ok, %Actor{} = new_actor} <- Actors.update_actor(old_actor, args),
|
||||
{:ok, _} <-
|
||||
@@ -57,6 +58,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
@public_ap "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Actor.t(), Actor.t(), boolean, map) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Actor.t()}
|
||||
def delete(
|
||||
%Actor{
|
||||
followers_url: followers_url,
|
||||
@@ -100,10 +103,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Actor.t()) :: Actor.t() | nil
|
||||
def actor(%Actor{} = actor), do: actor
|
||||
|
||||
@spec actor(Actor.t()) :: Actor.t() | nil
|
||||
def group_actor(%Actor{} = actor), do: actor
|
||||
|
||||
@spec permissions(Actor.t()) :: Permission.t()
|
||||
def permissions(%Actor{} = _group) do
|
||||
%Permission{
|
||||
access: :member,
|
||||
@@ -113,7 +119,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
}
|
||||
end
|
||||
|
||||
@spec join(Actor.t(), Actor.t(), boolean(), map()) :: {:ok, map(), Member.t()}
|
||||
@spec join(Actor.t(), Actor.t(), boolean(), map()) :: {:ok, ActivityStreams.t(), Member.t()}
|
||||
def join(%Actor{type: :Group} = group, %Actor{} = actor, _local, additional) do
|
||||
with role <-
|
||||
additional
|
||||
@@ -153,6 +159,10 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
end
|
||||
end
|
||||
|
||||
@spec follow(Actor.t(), Actor.t(), boolean, map) ::
|
||||
{:accept, any}
|
||||
| {:ok, ActivityStreams.t(), Follower.t()}
|
||||
| {:error, :no_person, String.t()}
|
||||
def follow(%Actor{} = follower_actor, %Actor{type: type} = followed, _local, additional)
|
||||
when type != :Person do
|
||||
with {:ok, %Follower{} = follower} <-
|
||||
@@ -165,6 +175,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
|
||||
def follow(_, _, _, _), do: {:error, :no_person, "Only group and instances can be followed"}
|
||||
|
||||
@spec prepare_args_for_actor(map) :: map
|
||||
defp prepare_args_for_actor(args) do
|
||||
args
|
||||
|> maybe_sanitize_username()
|
||||
@@ -191,8 +202,14 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
defp maybe_sanitize_summary(args), do: args
|
||||
|
||||
# Set the participant to approved if the default role for new participants is :participant
|
||||
@spec approve_if_default_role_is_member(Actor.t(), Actor.t(), map(), Member.t(), atom()) ::
|
||||
{:ok, map(), Member.t()}
|
||||
@spec approve_if_default_role_is_member(
|
||||
Actor.t(),
|
||||
Actor.t(),
|
||||
ActivityStreams.t(),
|
||||
Member.t(),
|
||||
MemberRole.t()
|
||||
) ::
|
||||
{:ok, ActivityStreams.t(), Member.t()}
|
||||
defp approve_if_default_role_is_member(
|
||||
%Actor{type: :Group} = group,
|
||||
%Actor{} = actor,
|
||||
@@ -202,7 +219,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
) do
|
||||
if is_nil(group.domain) && !is_nil(actor.domain) do
|
||||
cond do
|
||||
Mobilizon.Actors.get_default_member_role(group) === :member &&
|
||||
Mobilizon.Actors.get_default_member_role(group) == :member &&
|
||||
role == :member ->
|
||||
{:accept,
|
||||
ActivityPub.accept(
|
||||
@@ -212,7 +229,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
%{"actor" => group.url}
|
||||
)}
|
||||
|
||||
Mobilizon.Actors.get_default_member_role(group) === :not_approved &&
|
||||
Mobilizon.Actors.get_default_member_role(group) == :not_approved &&
|
||||
role == :not_approved ->
|
||||
Scheduler.pending_membership_notification(group)
|
||||
{:ok, activity_data, member}
|
||||
@@ -225,6 +242,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
|
||||
end
|
||||
end
|
||||
|
||||
@spec approve_if_manually_approves_followers(Follower.t(), ActivityStreams.t()) ::
|
||||
{:accept, any} | {:ok, ActivityStreams.t(), Follower.t()}
|
||||
defp approve_if_manually_approves_followers(
|
||||
%Follower{} = follower,
|
||||
follow_as_data
|
||||
|
||||
@@ -6,6 +6,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
alias Mobilizon.Events.{Event, EventOptions}
|
||||
alias Mobilizon.Federation.ActivityPub.{Audience, Permission}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.GraphQL.API.Utils, as: APIUtils
|
||||
@@ -20,7 +21,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Comment.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with args <- prepare_args_for_comment(args),
|
||||
:ok <- make_sure_event_allows_commenting(args),
|
||||
@@ -41,7 +42,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Comment.t(), map(), map()) :: {:ok, Comment.t(), Activity.t()} | any()
|
||||
@spec update(Comment.t(), map(), map()) :: {:ok, Comment.t(), ActivityStream.t()}
|
||||
def update(%Comment{} = old_comment, args, additional) do
|
||||
with args <- prepare_args_for_comment_update(args),
|
||||
{:ok, %Comment{} = new_comment} <- Discussions.update_comment(old_comment, args),
|
||||
@@ -60,7 +61,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Comment.t(), Actor.t(), boolean, map()) :: {:ok, Comment.t()}
|
||||
@spec delete(Comment.t(), Actor.t(), boolean, map()) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Comment.t()}
|
||||
def delete(
|
||||
%Comment{url: url, id: comment_id},
|
||||
%Actor{} = actor,
|
||||
@@ -91,6 +93,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Comment.t()) :: Actor.t() | nil
|
||||
def actor(%Comment{actor: %Actor{} = actor}), do: actor
|
||||
|
||||
def actor(%Comment{actor_id: actor_id}) when not is_nil(actor_id),
|
||||
@@ -98,6 +101,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
|
||||
def actor(_), do: nil
|
||||
|
||||
@spec group_actor(Comment.t()) :: Actor.t() | nil
|
||||
def group_actor(%Comment{attributed_to: %Actor{} = group}), do: group
|
||||
|
||||
def group_actor(%Comment{attributed_to_id: attributed_to_id}) when not is_nil(attributed_to_id),
|
||||
@@ -105,6 +109,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
|
||||
def group_actor(_), do: nil
|
||||
|
||||
@spec permissions(Comment.t()) :: Permission.t()
|
||||
def permissions(%Comment{}),
|
||||
do: %Permission{
|
||||
access: :member,
|
||||
@@ -114,6 +119,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
}
|
||||
|
||||
# Prepare and sanitize arguments for comments
|
||||
@spec prepare_args_for_comment(map) :: map
|
||||
defp prepare_args_for_comment(args) do
|
||||
with in_reply_to_comment <-
|
||||
args |> Map.get(:in_reply_to_comment_id) |> Discussions.get_comment_with_preload(),
|
||||
@@ -150,6 +156,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
end
|
||||
end
|
||||
|
||||
@spec prepare_args_for_comment_update(map) :: map
|
||||
defp prepare_args_for_comment_update(args) do
|
||||
with {text, mentions, tags} <-
|
||||
APIUtils.make_content_html(
|
||||
@@ -174,6 +181,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
|
||||
defp handle_event_for_comment(nil), do: nil
|
||||
|
||||
@spec maybe_publish_graphql_subscription(String.t() | integer() | nil) :: :ok
|
||||
defp maybe_publish_graphql_subscription(nil), do: :ok
|
||||
|
||||
defp maybe_publish_graphql_subscription(discussion_id) do
|
||||
@@ -186,6 +194,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Comments do
|
||||
end
|
||||
end
|
||||
|
||||
@spec make_sure_event_allows_commenting(%{actor_id: String.t() | integer, event: Event.t()}) ::
|
||||
:ok | {:error, :event_comments_are_closed}
|
||||
defp make_sure_event_allows_commenting(%{
|
||||
actor_id: actor_id,
|
||||
event: %Event{
|
||||
|
||||
@@ -6,6 +6,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
alias Mobilizon.Discussions.{Comment, Discussion}
|
||||
alias Mobilizon.Federation.ActivityPub.{Audience, Permission}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.GraphQL.API.Utils, as: APIUtils
|
||||
alias Mobilizon.Service.Activity.Discussion, as: DiscussionActivity
|
||||
@@ -16,7 +17,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Discussion.t(), ActivityStream.t()}
|
||||
def create(%{discussion_id: discussion_id} = args, additional) when not is_nil(discussion_id) do
|
||||
with args <- prepare_args(args),
|
||||
%Discussion{} = discussion <- Discussions.get_discussion(discussion_id),
|
||||
@@ -39,7 +40,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Discussion.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with args <- prepare_args(args),
|
||||
{:ok, %Discussion{} = discussion} <-
|
||||
@@ -56,7 +57,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Discussion.t(), map(), map()) :: {:ok, Discussion.t(), Activity.t()} | any()
|
||||
@spec update(Discussion.t(), map(), map()) :: {:ok, Discussion.t(), ActivityStream.t()}
|
||||
def update(%Discussion{} = old_discussion, args, additional) do
|
||||
with {:ok, %Discussion{} = new_discussion} <-
|
||||
Discussions.update_discussion(old_discussion, args),
|
||||
@@ -80,7 +81,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Discussion.t(), Actor.t(), boolean, map()) :: {:ok, Discussion.t()}
|
||||
@spec delete(Discussion.t(), Actor.t(), boolean, map()) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Discussion.t()}
|
||||
def delete(
|
||||
%Discussion{actor: group, url: url} = discussion,
|
||||
%Actor{} = actor,
|
||||
@@ -106,10 +108,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Discussion.t()) :: Actor.t() | nil
|
||||
def actor(%Discussion{creator_id: creator_id}), do: Actors.get_actor(creator_id)
|
||||
|
||||
@spec group_actor(Discussion.t()) :: Actor.t() | nil
|
||||
def group_actor(%Discussion{actor_id: actor_id}), do: Actors.get_actor(actor_id)
|
||||
|
||||
@spec permissions(Discussion.t()) :: Permission.t()
|
||||
def permissions(%Discussion{}) do
|
||||
%Permission{access: :member, create: :member, update: :moderator, delete: :moderator}
|
||||
end
|
||||
@@ -123,6 +128,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Discussions do
|
||||
:ok
|
||||
end
|
||||
|
||||
@spec prepare_args(map) :: map
|
||||
defp prepare_args(args) do
|
||||
{text, _mentions, _tags} =
|
||||
APIUtils.make_content_html(
|
||||
|
||||
@@ -15,7 +15,7 @@ alias Mobilizon.Federation.ActivityPub.Types.{
|
||||
}
|
||||
|
||||
alias Mobilizon.Actors.{Actor, Member}
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
alias Mobilizon.Discussions.{Comment, Discussion}
|
||||
alias Mobilizon.Federation.ActivityPub.Permission
|
||||
alias Mobilizon.Posts.Post
|
||||
@@ -28,7 +28,19 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Entity do
|
||||
@moduledoc """
|
||||
ActivityPub entity behaviour
|
||||
"""
|
||||
@type t :: %{id: String.t()}
|
||||
@type t :: %{id: String.t(), url: String.t()}
|
||||
|
||||
@type entities ::
|
||||
Actor.t()
|
||||
| Member.t()
|
||||
| Event.t()
|
||||
| Participant.t()
|
||||
| Comment.t()
|
||||
| Discussion.t()
|
||||
| Post.t()
|
||||
| Resource.t()
|
||||
| Todo.t()
|
||||
| TodoList.t()
|
||||
|
||||
@callback create(data :: any(), additionnal :: map()) ::
|
||||
{:ok, t(), ActivityStream.t()}
|
||||
|
||||
@@ -3,8 +3,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events, as: EventsManager
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Events.{Event, Participant, ParticipantRole}
|
||||
alias Mobilizon.Federation.{ActivityPub, ActivityStream}
|
||||
alias Mobilizon.Federation.ActivityPub.{Audience, Permission}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
|
||||
@@ -22,7 +22,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Event.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with args <- prepare_args_for_event(args),
|
||||
{:ok, %Event{} = event} <- EventsManager.create_event(args),
|
||||
@@ -38,7 +38,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Event.t(), map(), map()) :: {:ok, Event.t(), Activity.t()} | any()
|
||||
@spec update(Event.t(), map(), map()) :: {:ok, Event.t(), ActivityStream.t()}
|
||||
def update(%Event{} = old_event, args, additional) do
|
||||
with args <- prepare_args_for_event(args),
|
||||
{:ok, %Event{} = new_event} <- EventsManager.update_event(old_event, args),
|
||||
@@ -59,7 +59,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Event.t(), Actor.t(), boolean, map()) :: {:ok, Event.t()}
|
||||
@spec delete(Event.t(), Actor.t(), boolean, map()) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Event.t()}
|
||||
def delete(%Event{url: url} = event, %Actor{} = actor, _local, _additionnal) do
|
||||
activity_data = %{
|
||||
"type" => "Delete",
|
||||
@@ -82,6 +83,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Event.t()) :: Actor.t() | nil
|
||||
def actor(%Event{organizer_actor: %Actor{} = actor}), do: actor
|
||||
|
||||
def actor(%Event{organizer_actor_id: organizer_actor_id}),
|
||||
@@ -89,6 +91,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
|
||||
def actor(_), do: nil
|
||||
|
||||
@spec group_actor(Event.t()) :: Actor.t() | nil
|
||||
def group_actor(%Event{attributed_to: %Actor{} = group}), do: group
|
||||
|
||||
def group_actor(%Event{attributed_to_id: attributed_to_id}) when not is_nil(attributed_to_id),
|
||||
@@ -96,6 +99,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
|
||||
def group_actor(_), do: nil
|
||||
|
||||
@spec permissions(Event.t()) :: Permission.t()
|
||||
def permissions(%Event{draft: draft, attributed_to_id: _attributed_to_id}) do
|
||||
%Permission{
|
||||
access: if(draft, do: nil, else: :member),
|
||||
@@ -105,9 +109,12 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
}
|
||||
end
|
||||
|
||||
@spec join(Event.t(), Actor.t(), boolean, map) ::
|
||||
{:ok, ActivityStreams.t(), Participant.t()}
|
||||
| {:error, :maximum_attendee_capacity_reached}
|
||||
def join(%Event{} = event, %Actor{} = actor, _local, additional) do
|
||||
with {:maximum_attendee_capacity, true} <-
|
||||
{:maximum_attendee_capacity, check_attendee_capacity(event)},
|
||||
{:maximum_attendee_capacity, check_attendee_capacity?(event)},
|
||||
role <-
|
||||
additional
|
||||
|> Map.get(:metadata, %{})
|
||||
@@ -133,12 +140,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
role
|
||||
)
|
||||
else
|
||||
{:maximum_attendee_capacity, err} ->
|
||||
{:maximum_attendee_capacity, err}
|
||||
{:maximum_attendee_capacity, false} ->
|
||||
{:error, :maximum_attendee_capacity_reached}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_attendee_capacity(%Event{options: options} = event) do
|
||||
@spec check_attendee_capacity?(Event.t()) :: boolean
|
||||
defp check_attendee_capacity?(%Event{options: options} = event) do
|
||||
with maximum_attendee_capacity <-
|
||||
Map.get(options, :maximum_attendee_capacity) || 0 do
|
||||
maximum_attendee_capacity == 0 ||
|
||||
@@ -147,6 +155,12 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
|
||||
# Set the participant to approved if the default role for new participants is :participant
|
||||
@spec approve_if_default_role_is_participant(
|
||||
Event.t(),
|
||||
ActivityStreams.t(),
|
||||
Participant.t(),
|
||||
ParticipantRole.t()
|
||||
) :: {:ok, ActivityStreams.t(), Participant.t()}
|
||||
defp approve_if_default_role_is_participant(event, activity_data, participant, role) do
|
||||
case event do
|
||||
%Event{attributed_to: %Actor{id: group_id, url: group_url}} ->
|
||||
@@ -171,9 +185,11 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
end
|
||||
|
||||
@spec do_approve(Event.t(), ActivityStreams.t(), Particpant.t(), ParticipantRole.t(), map()) ::
|
||||
{:accept, any} | {:ok, ActivityStreams.t(), Participant.t()}
|
||||
defp do_approve(event, activity_data, participant, role, additionnal) do
|
||||
cond do
|
||||
Mobilizon.Events.get_default_participant_role(event) === :participant &&
|
||||
Mobilizon.Events.get_default_participant_role(event) == :participant &&
|
||||
role == :participant ->
|
||||
{:accept,
|
||||
ActivityPub.accept(
|
||||
@@ -183,7 +199,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
additionnal
|
||||
)}
|
||||
|
||||
Mobilizon.Events.get_default_participant_role(event) === :not_approved &&
|
||||
Mobilizon.Events.get_default_participant_role(event) == :not_approved &&
|
||||
role == :not_approved ->
|
||||
Scheduler.pending_participation_notification(event)
|
||||
{:ok, activity_data, participant}
|
||||
@@ -194,6 +210,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
||||
end
|
||||
|
||||
# Prepare and sanitize arguments for events
|
||||
@spec prepare_args_for_event(map) :: map
|
||||
defp prepare_args_for_event(args) do
|
||||
# If title is not set: we are not updating it
|
||||
args =
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
defmodule Mobilizon.Federation.ActivityPub.Types.Members do
|
||||
@moduledoc false
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.{Actor, Member}
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Actors.{Actor, Member, MemberRole}
|
||||
alias Mobilizon.Federation.{ActivityPub, ActivityStream}
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Service.Activity.Member, as: MemberActivity
|
||||
alias Mobilizon.Web.Endpoint
|
||||
require Logger
|
||||
import Mobilizon.Federation.ActivityPub.Utils, only: [make_update_data: 2]
|
||||
|
||||
@spec update(Member.t(), map, map) :: {:ok, Member.t(), ActivityStream.t()}
|
||||
def update(
|
||||
%Member{
|
||||
parent: %Actor{id: group_id} = group,
|
||||
@@ -24,7 +25,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Members do
|
||||
when moderator_role in [:moderator, :administrator, :creator] <-
|
||||
{:has_rights_to_update_role, Actors.get_member(moderator_id, group_id)},
|
||||
{:is_only_admin, false} <-
|
||||
{:is_only_admin, check_admins_left(member_id, group_id, current_role, updated_role)},
|
||||
{:is_only_admin, check_admins_left?(member_id, group_id, current_role, updated_role)},
|
||||
{:ok, %Member{} = member} <-
|
||||
Actors.update_member(old_member, args),
|
||||
{:ok, _} <-
|
||||
@@ -56,6 +57,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Members do
|
||||
end
|
||||
|
||||
# Used only when a group is suspended
|
||||
@spec delete(Member.t(), Actor.t(), boolean(), map()) :: {:ok, Activity.t(), Member.t()}
|
||||
def delete(
|
||||
%Member{parent: %Actor{} = group, actor: %Actor{} = actor} = _member,
|
||||
%Actor{},
|
||||
@@ -66,13 +68,21 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Members do
|
||||
ActivityPub.leave(group, actor, local, %{force_member_removal: true})
|
||||
end
|
||||
|
||||
@spec actor(Member.t()) :: Actor.t() | nil
|
||||
def actor(%Member{actor_id: actor_id}),
|
||||
do: Actors.get_actor(actor_id)
|
||||
|
||||
@spec group_actor(Member.t()) :: Actor.t() | nil
|
||||
def group_actor(%Member{parent_id: parent_id}),
|
||||
do: Actors.get_actor(parent_id)
|
||||
|
||||
defp check_admins_left(member_id, group_id, current_role, updated_role) do
|
||||
@spec check_admins_left?(
|
||||
String.t() | integer,
|
||||
String.t() | integer,
|
||||
MemberRole.t(),
|
||||
MemberRole.t()
|
||||
) :: boolean
|
||||
defp check_admins_left?(member_id, group_id, current_role, updated_role) do
|
||||
Actors.is_only_administrator?(member_id, group_id) && current_role == :administrator &&
|
||||
updated_role != :administrator
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub.{Audience, Permission}
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Posts.Post
|
||||
@@ -17,6 +18,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
@public_ap "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, Post.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with args <- prepare_args(args),
|
||||
{:ok, %Post{attributed_to_id: group_id, author_id: creator_id} = post} <-
|
||||
@@ -37,6 +39,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Post.t(), map(), map()) :: {:ok, Post.t(), ActivityStream.t()}
|
||||
def update(%Post{} = post, args, additional) do
|
||||
with args <- prepare_args(args),
|
||||
{:ok, %Post{attributed_to_id: group_id, author_id: creator_id} = post} <-
|
||||
@@ -60,6 +63,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Post.t(), Actor.t(), boolean, map) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Post.t()}
|
||||
def delete(
|
||||
%Post{
|
||||
url: url,
|
||||
@@ -86,12 +91,15 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Post.t()) :: Actor.t() | nil
|
||||
def actor(%Post{author_id: author_id}),
|
||||
do: Actors.get_actor(author_id)
|
||||
|
||||
@spec group_actor(Post.t()) :: Actor.t() | nil
|
||||
def group_actor(%Post{attributed_to_id: attributed_to_id}),
|
||||
do: Actors.get_actor(attributed_to_id)
|
||||
|
||||
@spec permissions(Post.t()) :: Permission.t()
|
||||
def permissions(%Post{}) do
|
||||
%Permission{
|
||||
access: :member,
|
||||
@@ -101,6 +109,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
}
|
||||
end
|
||||
|
||||
@spec prepare_args(map()) :: map
|
||||
defp prepare_args(args) do
|
||||
args
|
||||
|> Map.update(:tags, [], &ConverterUtils.fetch_tags/1)
|
||||
|
||||
@@ -2,11 +2,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Reports do
|
||||
@moduledoc false
|
||||
alias Mobilizon.{Actors, Discussions, Reports}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Reports.Report
|
||||
alias Mobilizon.Service.Formatter.HTML
|
||||
require Logger
|
||||
|
||||
@spec flag(map(), boolean(), map()) :: {Report.t(), ActivityStream.t()}
|
||||
def flag(args, local \\ false, _additional \\ %{}) do
|
||||
with {:build_args, args} <- {:build_args, prepare_args_for_report(args)},
|
||||
{:create_report, {:ok, %Report{} = report}} <-
|
||||
@@ -18,6 +20,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Reports do
|
||||
end
|
||||
end
|
||||
|
||||
@spec prepare_args_for_report(map()) :: map()
|
||||
defp prepare_args_for_report(args) do
|
||||
with {:reporter, %Actor{} = reporter_actor} <-
|
||||
{:reporter, Actors.get_actor!(args.reporter_id)},
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub.Permission
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Resources.Resource
|
||||
alias Mobilizon.Service.Activity.Resource, as: ResourceActivity
|
||||
@@ -16,6 +17,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, Resource.t(), ActivityStream.t()}
|
||||
def create(%{type: type} = args, additional) do
|
||||
args =
|
||||
case type do
|
||||
@@ -66,6 +68,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Resource.t(), map(), map()) :: {:ok, Resource.t(), ActivityStream.t()}
|
||||
def update(
|
||||
%Resource{parent_id: old_parent_id} = old_resource,
|
||||
%{parent_id: parent_id} = args,
|
||||
@@ -104,6 +107,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
end
|
||||
end
|
||||
|
||||
@spec update(Resource.t(), map(), map()) :: {:ok, Resource.t(), ActivityStream.t()}
|
||||
def move(
|
||||
%Resource{parent_id: old_parent_id} = old_resource,
|
||||
%{parent_id: _new_parent_id} = args,
|
||||
@@ -142,6 +146,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec delete(Resource.t(), Actor.t(), boolean, map()) ::
|
||||
{:ok, ActivityStream.t(), Actor.t(), Resource.t()}
|
||||
def delete(
|
||||
%Resource{url: url, actor: %Actor{url: group_url, members_url: members_url}} = resource,
|
||||
%Actor{url: actor_url} = actor,
|
||||
@@ -166,11 +172,14 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Resources do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Todo.t()) :: Actor.t() | nil
|
||||
def actor(%Resource{creator_id: creator_id}),
|
||||
do: Actors.get_actor(creator_id)
|
||||
|
||||
@spec group_actor(Todo.t()) :: Actor.t() | nil
|
||||
def group_actor(%Resource{actor_id: actor_id}), do: Actors.get_actor(actor_id)
|
||||
|
||||
@spec permissions(TodoList.t()) :: Permission.t()
|
||||
def permissions(%Resource{}) do
|
||||
%Permission{access: :member, create: :member, update: :member, delete: :member}
|
||||
end
|
||||
|
||||
@@ -13,7 +13,9 @@ defmodule Mobilizon.Federation.ActivityPub.Types.TodoLists do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) ::
|
||||
{:ok, TodoList.t(), ActivityStream.t()}
|
||||
| {:error, :group_not_found | Ecto.Changeset.t()}
|
||||
def create(args, additional) do
|
||||
with {:ok, %TodoList{actor_id: group_id} = todo_list} <- Todos.create_todo_list(args),
|
||||
{:ok, %Actor{} = group} <- Actors.get_group_by_actor_id(group_id),
|
||||
@@ -26,7 +28,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.TodoLists do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(TodoList.t(), map, map) :: {:ok, TodoList.t(), Activity.t()} | any
|
||||
@spec update(TodoList.t(), map, map) :: {:ok, TodoList.t(), ActivityStream.t()} | any
|
||||
def update(%TodoList{} = old_todo_list, args, additional) do
|
||||
with {:ok, %TodoList{actor_id: group_id} = todo_list} <-
|
||||
Todos.update_todo_list(old_todo_list, args),
|
||||
@@ -65,10 +67,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.TodoLists do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(TodoList.t()) :: nil
|
||||
def actor(%TodoList{}), do: nil
|
||||
|
||||
@spec group_actor(TodoList.t()) :: Actor.t() | nil
|
||||
def group_actor(%TodoList{actor_id: actor_id}), do: Actors.get_actor(actor_id)
|
||||
|
||||
@spec permissions(TodoList.t()) :: Permission.t()
|
||||
def permissions(%TodoList{}) do
|
||||
%Permission{access: :member, create: :member, update: :member, delete: :member}
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub.Permission
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
alias Mobilizon.Todos.{Todo, TodoList}
|
||||
import Mobilizon.Federation.ActivityPub.Utils, only: [make_create_data: 2, make_update_data: 2]
|
||||
@@ -12,7 +13,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
|
||||
@behaviour Entity
|
||||
|
||||
@impl Entity
|
||||
@spec create(map(), map()) :: {:ok, map()}
|
||||
@spec create(map(), map()) :: {:ok, Todo.t(), ActivityStream.t()}
|
||||
def create(args, additional) do
|
||||
with {:ok, %Todo{todo_list_id: todo_list_id, creator_id: creator_id} = todo} <-
|
||||
Todos.create_todo(args),
|
||||
@@ -30,7 +31,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
|
||||
end
|
||||
|
||||
@impl Entity
|
||||
@spec update(Todo.t(), map, map) :: {:ok, Todo.t(), Activity.t()} | any
|
||||
@spec update(Todo.t(), map, map) :: {:ok, Todo.t(), ActivityStream.t()}
|
||||
def update(%Todo{} = old_todo, args, additional) do
|
||||
with {:ok, %Todo{todo_list_id: todo_list_id} = todo} <- Todos.update_todo(old_todo, args),
|
||||
%TodoList{actor_id: group_id} = todo_list <- Todos.get_todo_list(todo_list_id),
|
||||
@@ -69,8 +70,10 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
|
||||
end
|
||||
end
|
||||
|
||||
@spec actor(Todo.t()) :: Actor.t() | nil
|
||||
def actor(%Todo{creator_id: creator_id}), do: Actors.get_actor(creator_id)
|
||||
|
||||
@spec group_actor(Todo.t()) :: Actor.t() | nil
|
||||
def group_actor(%Todo{todo_list_id: todo_list_id}) do
|
||||
case Todos.get_todo_list(todo_list_id) do
|
||||
%TodoList{actor_id: group_id} ->
|
||||
@@ -81,6 +84,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
|
||||
end
|
||||
end
|
||||
|
||||
@spec permissions(TodoList.t()) :: Permission.t()
|
||||
def permissions(%Todo{}) do
|
||||
%Permission{access: :member, create: :member, update: :member, delete: :member}
|
||||
end
|
||||
|
||||
@@ -29,7 +29,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map()) :: {:ok, map()}
|
||||
@spec as_to_model_data(map()) :: map() | {:error, :actor_not_allowed_type}
|
||||
def as_to_model_data(%{"type" => type} = data) when type in @allowed_types do
|
||||
avatar =
|
||||
download_picture(get_in(data, ["icon", "url"]), get_in(data, ["icon", "name"]), "avatar")
|
||||
@@ -64,7 +64,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
}
|
||||
end
|
||||
|
||||
def as_to_model_data(_), do: :error
|
||||
def as_to_model_data(_), do: {:error, :actor_not_allowed_type}
|
||||
|
||||
@doc """
|
||||
Convert an actor struct to an ActivityStream representation.
|
||||
@@ -135,7 +135,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
end
|
||||
end
|
||||
|
||||
@spec download_picture(String.t() | nil, String.t(), String.t()) :: map()
|
||||
@spec download_picture(String.t() | nil, String.t(), String.t()) :: map() | nil
|
||||
defp download_picture(nil, _name, _default_name), do: nil
|
||||
|
||||
defp download_picture(url, name, default_name) do
|
||||
|
||||
@@ -38,7 +38,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Comment do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map | {:error, any()}
|
||||
def as_to_model_data(object) do
|
||||
Logger.debug("We're converting raw ActivityStream data to a comment entity")
|
||||
Logger.debug(inspect(object))
|
||||
|
||||
@@ -8,6 +8,6 @@ defmodule Mobilizon.Federation.ActivityStream.Converter do
|
||||
|
||||
@type model_data :: map()
|
||||
|
||||
@callback as_to_model_data(as_data :: ActivityStream.t()) :: model_data()
|
||||
@callback as_to_model_data(as_data :: ActivityStream.t()) :: model_data() | {:error, any()}
|
||||
@callback model_to_as(model :: struct()) :: ActivityStream.t()
|
||||
end
|
||||
|
||||
@@ -12,6 +12,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Discussion do
|
||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Discussion, as: DiscussionConverter
|
||||
alias Mobilizon.Storage.Repo
|
||||
import Mobilizon.Service.Guards, only: [is_valid_string: 1]
|
||||
|
||||
require Logger
|
||||
|
||||
@@ -45,20 +46,27 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Discussion do
|
||||
end
|
||||
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
def as_to_model_data(%{"type" => "Note", "name" => name} = object) when not is_nil(name) do
|
||||
with creator_url <- Map.get(object, "actor"),
|
||||
{:ok, %Actor{id: creator_id, suspended: false}} <-
|
||||
@spec as_to_model_data(map) :: map() | {:error, any()}
|
||||
def as_to_model_data(%{"type" => "Note", "name" => name} = object) when is_valid_string(name) do
|
||||
case extract_actors(object) do
|
||||
%{actor_id: actor_id, creator_id: creator_id} ->
|
||||
%{actor_id: actor_id, creator_id: creator_id, title: name, url: object["id"]}
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
@spec extract_actors(map()) :: %{actor_id: String.t(), creator_id: String.t()} | {:error, any()}
|
||||
defp extract_actors(%{"actor" => creator_url, "attributedTo" => actor_url} = _object)
|
||||
when is_valid_string(creator_url) and is_valid_string(actor_url) do
|
||||
with {:ok, %Actor{id: creator_id, suspended: false}} <-
|
||||
ActivityPubActor.get_or_fetch_actor_by_url(creator_url),
|
||||
actor_url <- Map.get(object, "attributedTo"),
|
||||
{:ok, %Actor{id: actor_id, suspended: false}} <-
|
||||
ActivityPubActor.get_or_fetch_actor_by_url(actor_url) do
|
||||
%{
|
||||
title: name,
|
||||
actor_id: actor_id,
|
||||
creator_id: creator_id,
|
||||
url: object["id"]
|
||||
}
|
||||
%{actor_id: actor_id, creator_id: creator_id}
|
||||
else
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map()} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map() | {:error, any()} | :error
|
||||
def as_to_model_data(object) do
|
||||
with {%Actor{id: actor_id}, attributed_to} <-
|
||||
maybe_fetch_actor_and_attributed_to_id(object),
|
||||
|
||||
@@ -33,6 +33,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Member do
|
||||
}
|
||||
end
|
||||
|
||||
@spec as_to_model_data(map()) :: map()
|
||||
def as_to_model_data(%{
|
||||
"type" => "Member",
|
||||
"actor" => actor,
|
||||
|
||||
@@ -18,6 +18,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||
process_pictures: 2
|
||||
]
|
||||
|
||||
import Mobilizon.Service.Guards, only: [is_valid_string: 1]
|
||||
|
||||
@behaviour Converter
|
||||
|
||||
defimpl Convertible, for: Post do
|
||||
@@ -63,15 +65,15 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map() | {:error, any()}
|
||||
def as_to_model_data(
|
||||
%{"type" => "Article", "actor" => creator, "attributedTo" => group_uri} = object
|
||||
) do
|
||||
with {:ok, %Actor{id: attributed_to_id} = group} <- get_actor(group_uri),
|
||||
{:ok, %Actor{id: author_id}} <- get_actor(creator),
|
||||
{:visibility, visibility} <- {:visibility, get_visibility(object, group)},
|
||||
[description: description, picture_id: picture_id, medias: medias] <-
|
||||
process_pictures(object, attributed_to_id) do
|
||||
{:ok, %Actor{id: author_id}} <- get_actor(creator) do
|
||||
[description: description, picture_id: picture_id, medias: medias] =
|
||||
process_pictures(object, attributed_to_id)
|
||||
|
||||
%{
|
||||
title: object["name"],
|
||||
body: description,
|
||||
@@ -82,7 +84,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||
publish_at: object["published"],
|
||||
picture_id: picture_id,
|
||||
medias: medias,
|
||||
visibility: visibility,
|
||||
visibility: get_visibility(object, group),
|
||||
draft: object["draft"] == true
|
||||
}
|
||||
else
|
||||
@@ -92,11 +94,12 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||
end
|
||||
|
||||
@spec get_actor(String.t() | map() | nil) :: {:ok, Actor.t()} | {:error, String.t()}
|
||||
defp get_actor(nil), do: {:error, "nil property found for actor data"}
|
||||
|
||||
defp get_actor(actor),
|
||||
defp get_actor(actor) when is_valid_string(actor),
|
||||
do: actor |> Utils.get_url() |> ActivityPubActor.get_or_fetch_actor_by_url()
|
||||
|
||||
defp get_actor(_), do: {:error, "nil property found for actor data"}
|
||||
|
||||
@spec to_date(DateTime.t() | NaiveDateTime.t() | nil) :: String.t() | nil
|
||||
defp to_date(nil), do: nil
|
||||
defp to_date(%DateTime{} = date), do: DateTime.to_iso8601(date)
|
||||
defp to_date(%NaiveDateTime{} = date), do: NaiveDateTime.to_iso8601(date)
|
||||
|
||||
@@ -56,18 +56,17 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Resource do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map() | {:error, any()}
|
||||
def as_to_model_data(%{"type" => type, "actor" => creator, "attributedTo" => group} = object) do
|
||||
with {:ok, %Actor{id: actor_id, resources_url: resources_url}} <- get_actor(group),
|
||||
{:ok, %Actor{id: creator_id}} <- get_actor(creator),
|
||||
parent_id <- get_parent_id(object["context"], resources_url) do
|
||||
{:ok, %Actor{id: creator_id}} <- get_actor(creator) do
|
||||
data = %{
|
||||
title: object["name"],
|
||||
summary: object["summary"],
|
||||
url: object["id"],
|
||||
actor_id: actor_id,
|
||||
creator_id: creator_id,
|
||||
parent_id: parent_id,
|
||||
parent_id: get_parent_id(object["context"], resources_url),
|
||||
published_at: object["published"]
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Todo do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map() | {:error, any()}
|
||||
def as_to_model_data(
|
||||
%{"type" => "Todo", "actor" => actor_url, "todoList" => todo_list_url} = object
|
||||
) do
|
||||
|
||||
@@ -37,7 +37,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.TodoList do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
@spec as_to_model_data(map) :: map() | {:error, :group_not_found}
|
||||
def as_to_model_data(%{"type" => "TodoList", "actor" => actor_url} = object) do
|
||||
case ActivityPubActor.get_or_fetch_actor_by_url(actor_url) do
|
||||
{:ok, %Actor{type: :Group, id: group_id} = _group} ->
|
||||
|
||||
@@ -19,7 +19,7 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
|
||||
@spec key_id_to_actor_url(String.t()) :: String.t()
|
||||
def key_id_to_actor_url(key_id) do
|
||||
%{path: path} =
|
||||
%URI{path: path} =
|
||||
uri =
|
||||
key_id
|
||||
|> URI.parse()
|
||||
@@ -29,7 +29,7 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
if is_nil(path) do
|
||||
uri
|
||||
else
|
||||
Map.put(uri, :path, String.trim_trailing(path, "/publickey"))
|
||||
%URI{uri | path: String.trim_trailing(path, "/publickey")}
|
||||
end
|
||||
|
||||
URI.to_string(uri)
|
||||
@@ -78,6 +78,9 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
end
|
||||
end
|
||||
|
||||
@spec fetch_public_key(Plug.Conn.t()) ::
|
||||
{:ok, String.t()}
|
||||
| {:error, :actor_fetch_error | :actor_not_fetchable | :pem_decode_error}
|
||||
def fetch_public_key(conn) do
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
actor_id <- key_id_to_actor_url(kid),
|
||||
@@ -87,6 +90,9 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
end
|
||||
end
|
||||
|
||||
@spec refetch_public_key(Plug.Conn.t()) ::
|
||||
{:ok, String.t()}
|
||||
| {:error, :actor_fetch_error | :actor_not_fetchable | :pem_decode_error}
|
||||
def refetch_public_key(conn) do
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
actor_id <- key_id_to_actor_url(kid),
|
||||
@@ -97,6 +103,7 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
end
|
||||
end
|
||||
|
||||
@spec sign(Actor.t(), map()) :: String.t()
|
||||
def sign(%Actor{domain: domain, keys: keys} = actor, headers) when is_nil(domain) do
|
||||
Logger.debug("Signing a payload on behalf of #{actor.url}")
|
||||
Logger.debug("headers")
|
||||
@@ -112,14 +119,17 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||
raise ArgumentError, message: "Can't do a signature on remote actor #{url}"
|
||||
end
|
||||
|
||||
@spec generate_date_header :: String.t()
|
||||
def generate_date_header, do: generate_date_header(NaiveDateTime.utc_now())
|
||||
|
||||
def generate_date_header(%NaiveDateTime{} = date) do
|
||||
Timex.format!(date, "{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
|
||||
end
|
||||
|
||||
@spec generate_request_target(String.t(), String.t()) :: String.t()
|
||||
def generate_request_target(method, path), do: "#{method} #{path}"
|
||||
|
||||
@spec build_digest(String.t()) :: String.t()
|
||||
def build_digest(body) do
|
||||
"SHA-256=#{:sha256 |> :crypto.hash(body) |> Base.encode64()}"
|
||||
end
|
||||
|
||||
@@ -66,10 +66,10 @@ defmodule Mobilizon.Federation.WebFinger do
|
||||
end
|
||||
end
|
||||
|
||||
@spec represent_actor(Actor.t()) :: struct()
|
||||
@spec represent_actor(Actor.t()) :: map()
|
||||
@spec represent_actor(Actor.t(), String.t()) :: map()
|
||||
def represent_actor(%Actor{} = actor), do: represent_actor(actor, "JSON")
|
||||
|
||||
@spec represent_actor(Actor.t(), String.t()) :: struct()
|
||||
def represent_actor(%Actor{} = actor, "JSON") do
|
||||
links =
|
||||
[
|
||||
@@ -141,11 +141,15 @@ defmodule Mobilizon.Federation.WebFinger do
|
||||
@doc """
|
||||
Fetches the Extensible Resource Descriptor endpoint `/.well-known/host-meta` to find the Webfinger endpoint (usually `/.well-known/webfinger?resource=`)
|
||||
"""
|
||||
@spec find_webfinger_endpoint(String.t()) :: String.t()
|
||||
@spec find_webfinger_endpoint(String.t()) ::
|
||||
{:ok, String.t()} | {:error, :link_not_found} | {:error, any()}
|
||||
def find_webfinger_endpoint(domain) when is_binary(domain) do
|
||||
with {:ok, %{body: body}} <- fetch_document("http://#{domain}/.well-known/host-meta"),
|
||||
link_template when is_binary(link_template) <- find_link_from_template(body) do
|
||||
{:ok, link_template}
|
||||
else
|
||||
{:error, :link_not_found} -> {:error, :link_not_found}
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user