Refactoring of Actors context

This commit is contained in:
miffigriffy
2019-09-09 00:52:49 +02:00
parent 3a4a006c44
commit 4418275223
36 changed files with 1145 additions and 1345 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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