move things around

This commit is contained in:
Moon Man 2024-09-06 11:51:19 +00:00
parent 1c0d0fcd8d
commit 97cedc73b6
7 changed files with 126 additions and 21 deletions

View File

@ -2,8 +2,8 @@ defmodule Vonbraun.ActivityPub.Handler.Accept do
@behaviour Vonbraun.ActivityPub.HandlerBehaviour @behaviour Vonbraun.ActivityPub.HandlerBehaviour
require Logger require Logger
alias Vonbraun.Util
alias Vonbraun.Ecto.Schema.Actor alias Vonbraun.Ecto.Schema.Actor
alias Vonbraun.ActivityPub.Object
@verb "Accept" @verb "Accept"
@ -41,7 +41,7 @@ defmodule Vonbraun.ActivityPub.Handler.Accept do
%{} %{}
) do ) do
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)}, with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
{:match, true} <- {:match, follow_actor_id == Object.my_id()}, {:match, true} <- {:match, follow_actor_id == Util.my_id()},
{: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}")

View File

@ -5,6 +5,7 @@ defmodule Vonbraun.ActivityPub.Handler.Follow do
alias Vonbraun.ActivityPubReq alias Vonbraun.ActivityPubReq
alias Vonbraun.Ecto.Schema.Actor alias Vonbraun.Ecto.Schema.Actor
alias Vonbraun.ActivityPub.Object alias Vonbraun.ActivityPub.Object
alias Vonbraun.Util
@verb "Follow" @verb "Follow"
@ -20,7 +21,7 @@ defmodule Vonbraun.ActivityPub.Handler.Follow do
actor = %{} actor = %{}
) )
when is_binary(follow_requester_id) and is_binary(follow_target) and is_binary(activity_id) do when is_binary(follow_requester_id) and is_binary(follow_target) and is_binary(activity_id) do
with {:valid_target, true} <- {:valid_target, Object.my_id() == follow_target}, with {:valid_target, true} <- {:valid_target, Util.my_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

View File

@ -3,7 +3,7 @@ defmodule Vonbraun.ActivityPub.Handler.Reject do
require Logger require Logger
alias Vonbraun.Ecto.Schema.Actor alias Vonbraun.Ecto.Schema.Actor
alias Vonbraun.ActivityPub.Object alias Vonbraun.Util
import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1] import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1]
@verb "Reject" @verb "Reject"
@ -16,7 +16,7 @@ defmodule Vonbraun.ActivityPub.Handler.Reject do
"object" => object = %{"type" => "Follow"} "object" => object = %{"type" => "Follow"}
}) do }) do
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)}, with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
{:match, true} <- {:match, follow_actor_id == Object.my_id()}, {:match, true} <- {:match, follow_actor_id == Util.my_id()},
{: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}")

View File

@ -3,7 +3,7 @@ defmodule Vonbraun.ActivityPub.Handler.Undo do
require Logger require Logger
alias Vonbraun.Ecto.Schema.Actor alias Vonbraun.Ecto.Schema.Actor
alias Vonbraun.ActivityPub.Object alias Vonbraun.Util
import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1] import Vonbraun.ActivityPub.Handler.Accept, only: [extract_follow_object_actor: 1]
@verb "Undo" @verb "Undo"
@ -14,7 +14,7 @@ defmodule Vonbraun.ActivityPub.Handler.Undo do
def handle(%{"type" => @verb, "actor" => actor_id, "object" => object = %{"type" => "Follow"}}) do def handle(%{"type" => @verb, "actor" => actor_id, "object" => object = %{"type" => "Follow"}}) do
with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)}, with {:actor, {:ok, follow_actor_id}} <- {:actor, extract_follow_object_actor(object)},
{:match, true} <- {:match, follow_actor_id == Object.my_id()}, {:match, true} <- {:match, follow_actor_id == Util.my_id()},
{: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}

View File

@ -2,17 +2,7 @@ defmodule Vonbraun.ActivityPub.Object do
@context "https://www.w3.org/ns/activitystreams" @context "https://www.w3.org/ns/activitystreams"
@public_to "https://www.w3.org/ns/activitystreams#Public" @public_to "https://www.w3.org/ns/activitystreams#Public"
@spec my_id() :: String.t() import Vonbraun.Util, only: [my_id: 0]
def my_id() do
domain = Application.fetch_env!(:vonbraun, :domain)
nickname = Application.fetch_env!(:vonbraun, :nickname)
"https://#{domain}/users/#{nickname}"
end
@spec my_key_id() :: String.t()
def my_key_id() do
"#{my_id()}#main-key"
end
def add_context(object = %{"@context" => context}) def add_context(object = %{"@context" => context})
when is_list(context) or is_binary(context) do when is_list(context) or is_binary(context) do
@ -112,6 +102,9 @@ defmodule Vonbraun.ActivityPub.Object do
to: to_follow_id to: to_follow_id
) )
@spec accept_follow_activity(binary(), binary(), :accept | :reject) :: %{
optional(<<_::16, _::_*8>>) => any()
}
def accept_follow_activity(followee_id, activity_id, type \\ :accept) def accept_follow_activity(followee_id, activity_id, type \\ :accept)
when is_binary(followee_id) and is_binary(activity_id) and type in [:accept, :reject] do when is_binary(followee_id) and is_binary(activity_id) and type in [:accept, :reject] do
activity_type = activity_type =
@ -132,4 +125,102 @@ defmodule Vonbraun.ActivityPub.Object do
activity(activity_type, accept_activity_id, object, to: followee_id) activity(activity_type, accept_activity_id, object, to: followee_id)
end end
def is_maybe_activitypub?(%{"@context" => @context}), do: true
def is_maybe_activitypub?(%{"@context" => context_list}) when is_list(context_list) do
Enum.reduce_while(context_list, false, fn
@context, _ ->
{:halt, true}
context = %{}, _ ->
if Enum.find(context, fn item -> elem(item, 1) == @context end) do
{:halt, true}
else
{:cont, false}
end
_, _ ->
{:cont, false}
end)
end
def is_maybe_activitypub?(_), do: false
@spec fix_ld_properties(any()) ::
{:error, :child_id | :child_type | :id | :list | :type | :unknown}
| {:ok, list(list() | map()) | map()}
@doc """
If an object has type or id convert them to "@type" and "@id" respectively.
This is so that AP objects conform to JSON-LD for our purposes even though
they don't have to in the outside world. If the properties don't exist, they
are not added. Also fixes the properties of an "object" value, if present.
"""
def fix_ld_properties(object = %{}) do
has_unadorned_id? = Map.has_key?(object, "id")
has_id? = Map.has_key?(object, "@id")
has_unadored_type? = Map.has_key?(object, "type")
has_type? = Map.has_key?(object, "@type")
cond do
has_unadorned_id? && has_id? ->
{:error, :id}
has_unadored_type? && has_type? ->
{:error, :type}
true ->
object =
if has_unadorned_id? do
id = Map.get(object, "id")
object |> Map.delete("id") |> Map.put("@id", id)
else
object
end
if has_unadored_type? do
type = Map.get(object, "type")
object |> Map.delete("type") |> Map.put("@type", type)
else
object
end
# I am just assuming here the object is a JSON-LD object, not sure yet
# if this is a valid assumption.
with {:object, child_object = %{}} <- {:object, Map.get(object, "object")},
{:valid, {:ok, child_object}} <- {:valid, fix_ld_properties(child_object)} do
{:ok, Map.put(object, "object", child_object)}
else
{:object, child_object} when is_nil(child_object) or is_binary(child_object) ->
{:ok, Map.put(object, "object", child_object)}
{:valid, {:error, :type}} ->
{:error, :child_type}
{:valid, {:error, :id}} ->
{:error, :child_id}
end
end
end
# I forgot why I wrote this lol.
def fix_ld_properties(list) when is_list(list) do
fixed_objects =
Enum.reduce_while(list, {:ok, []}, fn object, objects ->
case fix_ld_properties(object) do
{:ok, fixed_object} -> {:cont, [fixed_object | objects]}
{:error, _error} -> {:halt, :error}
end
end)
case fixed_objects do
:error ->
{:error, :list}
_ ->
{:ok, Enum.reverse(fixed_objects)}
end
end
def fix_ld_properties(_), do: {:error, :unknown}
end end

View File

@ -1,8 +1,8 @@
defmodule Vonbraun.ActivityPubReq do defmodule Vonbraun.ActivityPubReq do
require Logger require Logger
alias Vonbraun.Cache alias Vonbraun.Cache
alias Vonbraun.Util
alias Vonbraun.HTTPSignature alias Vonbraun.HTTPSignature
alias Vonbraun.ActivityPub.Object
@ttl :timer.minutes(1) @ttl :timer.minutes(1)
@ -19,7 +19,7 @@ defmodule Vonbraun.ActivityPubReq do
path path
end end
headers = HTTPSignature.add_get_signature(headers, Object.my_key_id(), target) headers = HTTPSignature.add_get_signature(headers, Util.my_key_id(), target)
Req.get(url, headers: headers) Req.get(url, headers: headers)
end end
@ -39,7 +39,7 @@ defmodule Vonbraun.ActivityPubReq do
path path
end end
headers = HTTPSignature.add_post_signature(headers, Object.my_key_id(), target, body) headers = HTTPSignature.add_post_signature(headers, Util.my_key_id(), target, body)
Logger.debug("POST payload is: `#{body}`") Logger.debug("POST payload is: `#{body}`")

13
lib/vonbraun/util.ex Normal file
View File

@ -0,0 +1,13 @@
defmodule Vonbraun.Util do
@spec my_id() :: String.t()
def my_id() do
domain = Application.fetch_env!(:vonbraun, :domain)
nickname = Application.fetch_env!(:vonbraun, :nickname)
"https://#{domain}/users/#{nickname}"
end
@spec my_key_id() :: String.t()
def my_key_id() do
"#{my_id()}#main-key"
end
end