Compare commits
2 Commits
6f9a4f42f3
...
8257c07d26
Author | SHA1 | Date |
---|---|---|
Moon Man | 8257c07d26 | |
Moon Man | 49d2ac5648 |
|
@ -19,11 +19,29 @@ defmodule Vonbraun.ActivityPub.Handler do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec handle(%{type: String.t()}, map()) :: :ok | {:ok, atom()} | {:error, any()}
|
@doc """
|
||||||
def handle(activity = %{"type" => type}, actor = %{}) when is_binary(type) do
|
Passed a list of types, gets the first handler that applies to a type.
|
||||||
Agent.get(__MODULE__, fn map ->
|
"""
|
||||||
func = Map.get(map, type, fn _, _ -> {:ok, :type} end)
|
def get_first_matching_handler(types) when is_list(types) do
|
||||||
apply(func, [activity, actor])
|
Agent.get(__MODULE__, fn handler_map ->
|
||||||
|
Enum.reduce_while(types, nil, fn
|
||||||
|
type, _ ->
|
||||||
|
case Map.get(handler_map, type) do
|
||||||
|
nil -> {:cont, nil}
|
||||||
|
func -> {:halt, func}
|
||||||
|
end
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec handle(%{type: String.t()}, map()) :: {:ok, atom()} | {:error, any()}
|
||||||
|
def handle(activity = %{"@type" => types}, actor = %{}) when is_list(types) do
|
||||||
|
case get_first_matching_handler(types) do
|
||||||
|
nil ->
|
||||||
|
{:ok, :ignore}
|
||||||
|
|
||||||
|
func ->
|
||||||
|
apply(func, [activity, actor])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,43 +5,54 @@ defmodule Vonbraun.ActivityPub.Handler.Accept do
|
||||||
alias Vonbraun.Util
|
alias Vonbraun.Util
|
||||||
alias Vonbraun.Ecto.Schema.Actor
|
alias Vonbraun.Ecto.Schema.Actor
|
||||||
|
|
||||||
@verb "Accept"
|
@verb "https://www.w3.org/ns/activitystreams#Accept"
|
||||||
|
@follow "https://www.w3.org/ns/activitystreams#Follow"
|
||||||
|
|
||||||
def type, do: @verb
|
def type, do: @verb
|
||||||
|
|
||||||
def extract_follow_object_actor(%{"type" => "Follow", "actor" => actor_id})
|
defp is_follow_object?(%{"@type" => types}) when is_list(types), do: @follow in types
|
||||||
when is_binary(actor_id) do
|
|
||||||
{:ok, actor_id}
|
# The actor is specified here so we can just use it.
|
||||||
|
@spec extract_follow_object_actor_id(map()) :: :error | {:error, :not_found} | {:ok, binary()}
|
||||||
|
def extract_follow_object_actor_id(object = %{"actor" => actor_value}) do
|
||||||
|
if is_follow_object?(object) do
|
||||||
|
Util.get_only_id(actor_value)
|
||||||
|
else
|
||||||
|
{:error, :not_found}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_follow_object_actor(%{"type" => "Follow", "id" => provided_follow_activity_id})
|
# Only the ID was provided, so extract actor from the ID.
|
||||||
when is_binary(provided_follow_activity_id) do
|
def extract_follow_object_actor_id(object = %{"@id" => _}) do
|
||||||
domain = Application.fetch_env!(:vonbraun, :domain)
|
domain = Application.fetch_env!(:vonbraun, :domain)
|
||||||
actual_activity_id_prefix = "https://#{domain}/id/follow:"
|
actual_activity_id_prefix = "https://#{domain}/id/follow:"
|
||||||
|
|
||||||
with ^actual_activity_id_prefix <> actor_id <- provided_follow_activity_id do
|
with {:ok, provided_follow_activity_id} <- Util.get_only_id(object),
|
||||||
{:ok, actor_id}
|
^actual_activity_id_prefix <> raw_actor_id <- provided_follow_activity_id do
|
||||||
|
{:ok, URI.decode(raw_actor_id)}
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
{:error, :not_found}
|
{:error, :not_found}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_follow_object_actor(_) do
|
def extract_follow_object_actor_id(_) do
|
||||||
{:error, :not_found}
|
{:error, :not_found}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Lots of kinds of things can be accepted but for right now only follows.
|
# Lots of kinds of things can be accepted but for right now only follows.
|
||||||
def handle(
|
def handle(
|
||||||
%{
|
%{
|
||||||
"type" => @verb,
|
"actor" => actor_value,
|
||||||
"actor" => actor_id,
|
"object" => object_value
|
||||||
"object" => object = %{"type" => "Follow"}
|
|
||||||
},
|
},
|
||||||
%{}
|
%{}
|
||||||
) do
|
) do
|
||||||
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
|
my_id = Util.my_id()
|
||||||
{:match, true} <- {:match, follow_actor_id == Util.my_id()},
|
|
||||||
|
with {:object, {:ok, object}} <- {:object, Util.get_only_property(object_value)},
|
||||||
|
{:actor, {:ok, ^my_id}} <- {:actor, extract_follow_object_actor_id(object)},
|
||||||
|
{:actor_id, {:ok, actor_id}} <- {:actor_id, Util.get_only_id(actor_value)},
|
||||||
{:asked, {:ok, %Actor{:blocked => nil, :following_state => "accepted"}}} <-
|
{:asked, {:ok, %Actor{:blocked => nil, :following_state => "accepted"}}} <-
|
||||||
{:asked, Actor.mark_pending_follow(actor_id, "accepted", force: true)} do
|
{:asked, Actor.mark_pending_follow(actor_id, "accepted", force: true)} do
|
||||||
Logger.info("Now following: #{actor_id}")
|
Logger.info("Now following: #{actor_id}")
|
||||||
|
@ -55,7 +66,7 @@ defmodule Vonbraun.ActivityPub.Handler.Accept do
|
||||||
|
|
||||||
{:asked, {:ok, %Actor{:blocked => nil, :following_state => following_state}}} ->
|
{:asked, {:ok, %Actor{:blocked => nil, :following_state => following_state}}} ->
|
||||||
Logger.error(
|
Logger.error(
|
||||||
"Weird following state after received Accept: #{following_state} from actor: #{actor_id} this should not happen."
|
"Weird following state after received Accept: #{following_state} from actor: #{inspect(actor_value)} this should not happen."
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, :following_state}
|
{:error, :following_state}
|
||||||
|
@ -63,7 +74,10 @@ defmodule Vonbraun.ActivityPub.Handler.Accept do
|
||||||
{:actor, {:error, _error}} ->
|
{:actor, {:error, _error}} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
{:match, false} ->
|
{:actor_id, :error} ->
|
||||||
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
|
{:object, :error} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule Vonbraun.ActivityPub.Handler.Delete do
|
defmodule Vonbraun.ActivityPub.Handler.Delete do
|
||||||
@behaviour Vonbraun.ActivityPub.HandlerBehaviour
|
@behaviour Vonbraun.ActivityPub.HandlerBehaviour
|
||||||
|
|
||||||
@verb "Delete"
|
@verb "https://www.w3.org/ns/activitystreams#Delete"
|
||||||
|
|
||||||
def type, do: @verb
|
def type, do: @verb
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,23 @@ defmodule Vonbraun.ActivityPub.Handler.Follow do
|
||||||
alias Vonbraun.ActivityPub.Object
|
alias Vonbraun.ActivityPub.Object
|
||||||
alias Vonbraun.Util
|
alias Vonbraun.Util
|
||||||
|
|
||||||
@verb "Follow"
|
@verb "https://www.w3.org/ns/activitystreams#Follow"
|
||||||
|
|
||||||
def type, do: @verb
|
def type, do: @verb
|
||||||
|
|
||||||
def handle(
|
def handle(
|
||||||
%{
|
activity = %{
|
||||||
"id" => activity_id,
|
"actor" => actor_value,
|
||||||
"type" => @verb,
|
|
||||||
"actor" => follow_requester_id,
|
|
||||||
"object" => follow_target
|
"object" => follow_target
|
||||||
},
|
},
|
||||||
actor = %{}
|
actor = %{}
|
||||||
)
|
)
|
||||||
when is_binary(follow_requester_id) and is_binary(follow_target) and is_binary(activity_id) do
|
when is_binary(follow_target) do
|
||||||
with {:valid_target, true} <- {:valid_target, Util.my_id() == follow_target},
|
my_id = Util.my_id()
|
||||||
|
|
||||||
|
with {:activity_id, {:ok, activity_id}} <- {:activity_id, Util.get_only_id(activity)},
|
||||||
|
{:actor_id, {:ok, follow_requester_id}} <- {:actor_id, Util.get_only_id(actor_value)},
|
||||||
|
{:valid_target, {:ok, ^my_id}} <- {:valid_target, Util.get_only_id(follow_target)},
|
||||||
{:add, {:ok, %Actor{:blocked => nil, :follows_me_state => follows_me_state}}}
|
{:add, {:ok, %Actor{:blocked => nil, :follows_me_state => follows_me_state}}}
|
||||||
when not is_nil(follows_me_state) <-
|
when not is_nil(follows_me_state) <-
|
||||||
{:add, Actor.maybe_add_follower(follow_requester_id)} do
|
{:add, Actor.maybe_add_follower(follow_requester_id)} do
|
||||||
|
@ -66,7 +68,13 @@ defmodule Vonbraun.ActivityPub.Handler.Follow do
|
||||||
{:ok, :ignored}
|
{:ok, :ignored}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{:valid_target, false} ->
|
{:actor_id, :error} ->
|
||||||
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
|
{:activity_id, :error} ->
|
||||||
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
|
{:valid_target, _} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
{:add, {:ok, %Actor{:blocked => blocked_ts}}} when not is_nil(blocked_ts) ->
|
{:add, {:ok, %Actor{:blocked => blocked_ts}}} when not is_nil(blocked_ts) ->
|
||||||
|
|
|
@ -4,19 +4,24 @@ defmodule Vonbraun.ActivityPub.Handler.Reject do
|
||||||
require Logger
|
require Logger
|
||||||
alias Vonbraun.Ecto.Schema.Actor
|
alias Vonbraun.Ecto.Schema.Actor
|
||||||
alias Vonbraun.Util
|
alias Vonbraun.Util
|
||||||
import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1]
|
|
||||||
|
|
||||||
@verb "Reject"
|
import Vonbraun.ActivityPub.Handler.Accept,
|
||||||
|
only: [extract_follow_object_actor_id: 1]
|
||||||
|
|
||||||
|
@verb "https://www.w3.org/ns/activitystreams#Reject"
|
||||||
|
|
||||||
def type, do: @verb
|
def type, do: @verb
|
||||||
|
|
||||||
# Lots of kinds of things can be rejected but for right now only follows.
|
# Lots of kinds of things can be rejected but for right now only follows.
|
||||||
def handle(%{
|
def handle(%{
|
||||||
"type" => @verb,
|
"actor" => actor_value,
|
||||||
"actor" => actor_id,
|
"object" => object_value
|
||||||
"object" => object = %{"type" => "Follow"}
|
|
||||||
}) do
|
}) do
|
||||||
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
|
my_id = Util.my_id()
|
||||||
{:match, true} <- {:match, follow_actor_id == Util.my_id()},
|
|
||||||
|
with {:object, {:ok, object}} <- {:object, Util.get_only_property(object_value)},
|
||||||
|
{:actor, {:ok, ^my_id}} <- {:actor, extract_follow_object_actor_id(object)},
|
||||||
|
{:actor_id, {:ok, actor_id}} <- {:actor_id, Util.get_only_id(actor_value)},
|
||||||
{:asked, {:ok, %Actor{:blocked => nil, :following_state => "accepted"}}} <-
|
{:asked, {:ok, %Actor{:blocked => nil, :following_state => "accepted"}}} <-
|
||||||
{:asked, Actor.mark_pending_follow(actor_id, "rejected", force: true)} do
|
{:asked, Actor.mark_pending_follow(actor_id, "rejected", force: true)} do
|
||||||
Logger.info("Now following: #{actor_id}")
|
Logger.info("Now following: #{actor_id}")
|
||||||
|
@ -30,7 +35,7 @@ defmodule Vonbraun.ActivityPub.Handler.Reject do
|
||||||
|
|
||||||
{:asked, {:ok, %Actor{:blocked => nil, :following_state => following_state}}} ->
|
{:asked, {:ok, %Actor{:blocked => nil, :following_state => following_state}}} ->
|
||||||
Logger.error(
|
Logger.error(
|
||||||
"Weird following state after received Accept: #{following_state} from actor: #{actor_id} this should not happen."
|
"Weird following state after received Accept: #{following_state} from actor: #{inspect(actor_value)} this should not happen."
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, :following_state}
|
{:error, :following_state}
|
||||||
|
@ -38,7 +43,10 @@ defmodule Vonbraun.ActivityPub.Handler.Reject do
|
||||||
{:actor, {:error, _error}} ->
|
{:actor, {:error, _error}} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
{:match, false} ->
|
{:actor_id, :error} ->
|
||||||
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
|
{:object, :error} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,17 +4,20 @@ defmodule Vonbraun.ActivityPub.Handler.Undo do
|
||||||
require Logger
|
require Logger
|
||||||
alias Vonbraun.Ecto.Schema.Actor
|
alias Vonbraun.Ecto.Schema.Actor
|
||||||
alias Vonbraun.Util
|
alias Vonbraun.Util
|
||||||
import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1]
|
import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor_id: 1]
|
||||||
|
|
||||||
@verb "Undo"
|
@verb "https://www.w3.org/ns/activitystreams#Undo"
|
||||||
|
|
||||||
def type, do: @verb
|
def type, do: @verb
|
||||||
|
|
||||||
# Lots of different kinds of things can be undone.
|
# Lots of different kinds of things can be undone.
|
||||||
|
|
||||||
def handle(%{"type" => @verb, "actor" => actor_id, "object" => object = %{"type" => "Follow"}}) do
|
def handle(%{"actor" => actor_value, "object" => object_value}) do
|
||||||
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
|
my_id = Util.my_id()
|
||||||
{:match, true} <- {:match, follow_actor_id == Util.my_id()},
|
|
||||||
|
with {:object, {:ok, object}} <- {:object, Util.get_only_property(object_value)},
|
||||||
|
{:actor, {:ok, ^my_id}} <- {:actor, extract_follow_object_actor_id(object)},
|
||||||
|
{:actor_id, {:ok, actor_id}} <- {:actor_id, Util.get_only_id(actor_value)},
|
||||||
{:asked, {:ok, %Actor{:following_state => nil}}} <-
|
{:asked, {:ok, %Actor{:following_state => nil}}} <-
|
||||||
{:asked, Actor.remove_follower(actor_id)} do
|
{:asked, Actor.remove_follower(actor_id)} do
|
||||||
{:ok, :removed_follower}
|
{:ok, :removed_follower}
|
||||||
|
@ -22,15 +25,18 @@ defmodule Vonbraun.ActivityPub.Handler.Undo do
|
||||||
{:asked, {:error, error}} ->
|
{:asked, {:error, error}} ->
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
|
||||||
{:match, false} ->
|
{:actor_id, :error} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
{:actor, {:error, _error}} ->
|
{:actor, {:error, _error}} ->
|
||||||
{:ok, :unauthorized}
|
{:ok, :unauthorized}
|
||||||
|
|
||||||
|
{:object, :error} ->
|
||||||
|
{:ok, :unauthorized}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle(%{"type" => @verb}, %{}) do
|
def handle(%{}, %{}) do
|
||||||
{:ok, :unknown}
|
{:ok, :unknown}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ defmodule Vonbraun.Util do
|
||||||
"""
|
"""
|
||||||
def get_only_property([property]), do: {:ok, property}
|
def get_only_property([property]), do: {:ok, property}
|
||||||
|
|
||||||
def get_only_property(property) when is_list(property), do: {:error}
|
def get_only_property(property) when is_list(property), do: :error
|
||||||
|
|
||||||
def get_only_property(property), do: {:ok, property}
|
def get_only_property(property), do: {:ok, property}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue