Refactoring of Actors context
This commit is contained in:
@@ -113,6 +113,29 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@doc """
|
||||
Getting an actor from url, eventually creating it
|
||||
"""
|
||||
@spec get_or_fetch_by_url(String.t(), boolean) :: {:ok, Actor.t()} | {:error, String.t()}
|
||||
def get_or_fetch_by_url(url, preload \\ false) do
|
||||
case Actors.get_actor_by_url(url, preload) do
|
||||
{:ok, %Actor{} = actor} ->
|
||||
{:ok, actor}
|
||||
|
||||
_ ->
|
||||
case make_actor_from_url(url, preload) do
|
||||
{:ok, %Actor{} = actor} ->
|
||||
{:ok, actor}
|
||||
|
||||
_ ->
|
||||
Logger.warn("Could not fetch by AP id")
|
||||
|
||||
{:error, "Could not fetch by AP id"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create an activity of type "Create"
|
||||
"""
|
||||
@@ -279,7 +302,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
"""
|
||||
def follow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, %Follower{url: follow_url}} <-
|
||||
Actor.follow(followed, follower, activity_id, false),
|
||||
Actors.follow(followed, follower, activity_id, false),
|
||||
activity_follow_id <-
|
||||
activity_id || follow_url,
|
||||
data <- make_follow_data(followed, follower, activity_follow_id),
|
||||
@@ -298,7 +321,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
"""
|
||||
@spec unfollow(Actor.t(), Actor.t(), String.t(), boolean()) :: {:ok, map()} | any()
|
||||
def unfollow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, %Follower{id: follow_id}} <- Actor.unfollow(followed, follower),
|
||||
with {:ok, %Follower{id: follow_id}} <- Actors.unfollow(followed, follower),
|
||||
# We recreate the follow activity
|
||||
data <-
|
||||
make_follow_data(
|
||||
@@ -466,7 +489,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
def make_actor_from_url(url, preload \\ false) do
|
||||
case fetch_and_prepare_actor_from_url(url) do
|
||||
{:ok, data} ->
|
||||
Actors.insert_or_update_actor(data, preload)
|
||||
Actors.upsert_actor(data, preload)
|
||||
|
||||
# Request returned 410
|
||||
{:error, :actor_deleted} ->
|
||||
@@ -529,7 +552,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
|
||||
followers =
|
||||
if actor.followers_url in activity.recipients do
|
||||
Actor.get_full_external_followers(actor)
|
||||
Actors.get_full_external_followers(actor)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@@ -4,7 +4,6 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Comment do
|
||||
|
||||
This module allows to convert events from ActivityStream format to our own internal one, and back
|
||||
"""
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.Comment, as: CommentModel
|
||||
alias Mobilizon.Events.Event
|
||||
@@ -20,7 +19,7 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Comment do
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map()) :: map()
|
||||
def as_to_model_data(object) do
|
||||
{:ok, %Actor{id: actor_id}} = Actors.get_or_fetch_by_url(object["actor"])
|
||||
{:ok, %Actor{id: actor_id}} = ActivityPub.get_or_fetch_by_url(object["actor"])
|
||||
Logger.debug("Inserting full comment")
|
||||
Logger.debug(inspect(object))
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ defmodule Mobilizon.Service.ActivityPub.Relay do
|
||||
|
||||
def follow(target_instance) do
|
||||
with %Actor{} = local_actor <- get_actor(),
|
||||
{:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
|
||||
{:ok, %Actor{} = target_actor} <- ActivityPub.get_or_fetch_by_url(target_instance),
|
||||
{:ok, activity} <- Follows.follow(local_actor, target_actor) do
|
||||
Logger.info("Relay: followed instance #{target_instance}; id=#{activity.data["id"]}")
|
||||
{:ok, activity}
|
||||
@@ -37,7 +37,7 @@ defmodule Mobilizon.Service.ActivityPub.Relay do
|
||||
|
||||
def unfollow(target_instance) do
|
||||
with %Actor{} = local_actor <- get_actor(),
|
||||
{:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
|
||||
{:ok, %Actor{} = target_actor} <- ActivityPub.get_or_fetch_by_url(target_instance),
|
||||
{:ok, activity} <- Follows.unfollow(local_actor, target_actor) do
|
||||
Logger.info("Relay: unfollowed instance #{target_instance}: id=#{activity.data["id"]}")
|
||||
{:ok, activity}
|
||||
@@ -50,7 +50,7 @@ defmodule Mobilizon.Service.ActivityPub.Relay do
|
||||
|
||||
def accept(target_instance) do
|
||||
with %Actor{} = local_actor <- get_actor(),
|
||||
{:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
|
||||
{:ok, %Actor{} = target_actor} <- ActivityPub.get_or_fetch_by_url(target_instance),
|
||||
{:ok, activity} <- Follows.accept(target_actor, local_actor) do
|
||||
{:ok, activity}
|
||||
end
|
||||
@@ -58,7 +58,7 @@ defmodule Mobilizon.Service.ActivityPub.Relay do
|
||||
|
||||
# def reject(target_instance) do
|
||||
# with %Actor{} = local_actor <- get_actor(),
|
||||
# {:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
|
||||
# {:ok, %Actor{} = target_actor} <- Activity.get_or_fetch_by_url(target_instance),
|
||||
# {:ok, activity} <- Follows.reject(target_actor, local_actor) do
|
||||
# {:ok, activity}
|
||||
# end
|
||||
|
||||
@@ -139,7 +139,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
|
||||
Logger.info("Handle incoming to create notes")
|
||||
|
||||
with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(data["actor"]) do
|
||||
with {:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(data["actor"]) do
|
||||
Logger.debug("found actor")
|
||||
Logger.debug(inspect(actor))
|
||||
|
||||
@@ -163,7 +163,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Event"} = object} = data) do
|
||||
Logger.info("Handle incoming to create event")
|
||||
|
||||
with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(data["actor"]) do
|
||||
with {:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(data["actor"]) do
|
||||
Logger.debug("found actor")
|
||||
Logger.debug(inspect(actor))
|
||||
|
||||
@@ -187,8 +187,8 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
def handle_incoming(
|
||||
%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = _data
|
||||
) do
|
||||
with {:ok, %Actor{} = followed} <- Actors.get_or_fetch_by_url(followed, true),
|
||||
{:ok, %Actor{} = follower} <- Actors.get_or_fetch_by_url(follower),
|
||||
with {:ok, %Actor{} = followed} <- ActivityPub.get_or_fetch_by_url(followed, true),
|
||||
{:ok, %Actor{} = follower} <- ActivityPub.get_or_fetch_by_url(follower),
|
||||
{:ok, activity, object} <- ActivityPub.follow(follower, followed, id, false) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
@@ -207,7 +207,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
} = data
|
||||
) do
|
||||
with actor_url <- get_actor(data),
|
||||
{:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor_url),
|
||||
{:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(actor_url),
|
||||
{:object_not_found, {:ok, activity, object}} <-
|
||||
{:object_not_found,
|
||||
do_handle_incoming_accept_following(accepted_object, actor) ||
|
||||
@@ -236,7 +236,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
%{"type" => "Reject", "object" => rejected_object, "actor" => _actor, "id" => id} = data
|
||||
) do
|
||||
with actor_url <- get_actor(data),
|
||||
{:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor_url),
|
||||
{:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(actor_url),
|
||||
{:object_not_found, {:ok, activity, object}} <-
|
||||
{:object_not_found,
|
||||
do_handle_incoming_reject_following(rejected_object, actor) ||
|
||||
@@ -279,7 +279,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data
|
||||
) do
|
||||
with actor <- get_actor(data),
|
||||
{:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
|
||||
{:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(actor),
|
||||
{:ok, object} <- fetch_obj_helper_as_activity_streams(object_id),
|
||||
public <- Visibility.is_public?(data),
|
||||
{:ok, activity, object} <- ActivityPub.announce(actor, object, id, false, public) do
|
||||
@@ -347,7 +347,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
} = data
|
||||
) do
|
||||
with actor <- get_actor(data),
|
||||
{:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
|
||||
{:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_by_url(actor),
|
||||
{:ok, object} <- fetch_obj_helper_as_activity_streams(object_id),
|
||||
{:ok, activity, object} <-
|
||||
ActivityPub.unannounce(actor, object, id, cancelled_activity_id, false) do
|
||||
@@ -451,7 +451,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
# } = data
|
||||
# ) do
|
||||
# with actor <- get_actor(data),
|
||||
# %Actor{} = actor <- Actors.get_or_fetch_by_url(actor),
|
||||
# %Actor{} = actor <- ActivityPub.get_or_fetch_by_url(actor),
|
||||
# {:ok, object} <- fetch_obj_helper(object_id) || fetch_obj_helper(object_id),
|
||||
# {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
|
||||
# {:ok, activity}
|
||||
|
||||
@@ -44,7 +44,7 @@ defmodule Mobilizon.Service.Export.Feed do
|
||||
@spec fetch_actor_event_feed(String.t()) :: String.t()
|
||||
defp fetch_actor_event_feed(name) do
|
||||
with %Actor{} = actor <- Actors.get_local_actor_by_name(name),
|
||||
{:visibility, true} <- {:visibility, Actor.public_visibility?(actor)},
|
||||
{:visibility, true} <- {:visibility, Actor.is_public_visibility(actor)},
|
||||
{:ok, events, _count} <- Events.get_public_events_for_actor(actor) do
|
||||
{:ok, build_actor_feed(actor, events)}
|
||||
else
|
||||
|
||||
@@ -44,7 +44,7 @@ defmodule Mobilizon.Service.Export.ICalendar do
|
||||
"""
|
||||
@spec export_public_actor(Actor.t()) :: String.t()
|
||||
def export_public_actor(%Actor{} = actor) do
|
||||
with true <- Actor.public_visibility?(actor),
|
||||
with true <- Actor.is_public_visibility(actor),
|
||||
{:ok, events, _} <- Events.get_public_events_for_actor(actor) do
|
||||
{:ok, %ICalendar{events: events |> Enum.map(&do_export_event/1)} |> ICalendar.to_ics()}
|
||||
end
|
||||
|
||||
@@ -7,20 +7,23 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
|
||||
@moduledoc """
|
||||
Adapter for the `HTTPSignatures` lib that handles signing and providing public keys to verify HTTPSignatures
|
||||
"""
|
||||
|
||||
@behaviour HTTPSignatures.Adapter
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Service.ActivityPub
|
||||
|
||||
require Logger
|
||||
|
||||
def key_id_to_actor_url(key_id) do
|
||||
uri =
|
||||
URI.parse(key_id)
|
||||
%{path: path} = uri =
|
||||
key_id
|
||||
|> URI.parse()
|
||||
|> Map.put(:fragment, nil)
|
||||
|
||||
uri =
|
||||
if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
|
||||
Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
|
||||
if not is_nil(path) do
|
||||
Map.put(uri, :path, String.trim_trailing(path, "/publickey"))
|
||||
else
|
||||
uri
|
||||
end
|
||||
@@ -28,11 +31,47 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
|
||||
URI.to_string(uri)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert internal PEM encoded keys to public key format.
|
||||
"""
|
||||
@spec prepare_public_key(String.t()) :: {:ok, tuple} | {:error, :pem_decode_error}
|
||||
def prepare_public_key(public_key_code) do
|
||||
case :public_key.pem_decode(public_key_code) do
|
||||
[public_key_entry] ->
|
||||
{:ok, :public_key.pem_entry_decode(public_key_entry)}
|
||||
|
||||
_ ->
|
||||
{:error, :pem_decode_error}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a public key for a given ActivityPub actor ID (url).
|
||||
"""
|
||||
@spec get_public_key_for_url(String.t()) ::
|
||||
{:ok, String.t()} | {:error, :actor_fetch_error | :pem_decode_error}
|
||||
def get_public_key_for_url(url) do
|
||||
with {:ok, %Actor{keys: keys}} <- ActivityPub.get_or_fetch_by_url(url),
|
||||
{:ok, public_key} <- prepare_public_key(keys) do
|
||||
{:ok, public_key}
|
||||
else
|
||||
{:error, :pem_decode_error} ->
|
||||
Logger.error("Error while decoding PEM")
|
||||
|
||||
{:error, :pem_decode_error}
|
||||
|
||||
_ ->
|
||||
Logger.error("Unable to fetch actor, so no keys for you")
|
||||
|
||||
{:error, :actor_fetch_error}
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_public_key(conn) do
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
actor_id <- key_id_to_actor_url(kid),
|
||||
:ok <- Logger.debug("Fetching public key for #{actor_id}"),
|
||||
{:ok, public_key} <- Actor.get_public_key_for_url(actor_id) do
|
||||
{:ok, public_key} <- get_public_key_for_url(actor_id) do
|
||||
{:ok, public_key}
|
||||
else
|
||||
e ->
|
||||
@@ -45,7 +84,7 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
|
||||
actor_id <- key_id_to_actor_url(kid),
|
||||
:ok <- Logger.debug("Refetching public key for #{actor_id}"),
|
||||
{:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id),
|
||||
{:ok, public_key} <- Actor.get_public_key_for_url(actor_id) do
|
||||
{:ok, public_key} <- get_public_key_for_url(actor_id) do
|
||||
{:ok, public_key}
|
||||
else
|
||||
e ->
|
||||
@@ -53,12 +92,12 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
|
||||
end
|
||||
end
|
||||
|
||||
def sign(%Actor{} = actor, headers) do
|
||||
def sign(%Actor{keys: keys} = actor, headers) do
|
||||
Logger.debug("Signing on behalf of #{actor.url}")
|
||||
Logger.debug("headers")
|
||||
Logger.debug(inspect(headers))
|
||||
|
||||
with {:ok, key} <- actor.keys |> Actor.prepare_public_key() do
|
||||
with {:ok, key} <- prepare_public_key(keys) do
|
||||
HTTPSignatures.sign(key, actor.url <> "#main-key", headers)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user