nulla/lib/nulla_web/controllers/activitypub/inbox_controller.ex
2025-07-05 18:47:36 +00:00

255 lines
6.1 KiB
Elixir

defmodule NullaWeb.ActivityPub.InboxController do
use NullaWeb, :controller
alias Nulla.Snowflake
alias Nulla.HTTPSignature
alias Nulla.Sender
alias Nulla.Utils
alias Nulla.Actors
alias Nulla.Relations
alias Nulla.Activities
def inbox(conn, %{
"id" => _create_id,
"type" => "Create",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _read_id,
"type" => "Read",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _update_id,
"type" => "Update",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _delete_id,
"type" => "Delete",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _add_id,
"type" => "Add",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _view_id,
"type" => "View",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _move_id,
"type" => "Move",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _undo_id,
"type" => "Undo",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => follow_id,
"type" => "Follow",
"actor" => actor_uri,
"object" => target_uri
}) do
accept_id = Snowflake.next_id()
with local_actor <- Actors.get_actor_by(ap_id: target_uri),
{:ok, remote_actor_json} <- Utils.fetch_remote_actor(actor_uri),
:ok <- HTTPSignature.verify(conn, remote_actor_json["publicKey"]["publicKeyPem"]) do
ap_id = remote_actor_json["id"]
username = remote_actor_json["preferredUsername"]
domain = URI.parse(remote_actor_json["id"]).host
remote_actor =
case Actors.get_actor_by(ap_id: ap_id) do
nil ->
params =
remote_actor_json
|> Map.put("ap_id", ap_id)
|> Map.delete("id")
|> Map.put("acct", "#{username}@#{domain}")
case Actors.create_actor(params) do
{:ok, actor} -> actor
{:error, error} -> {:error, error}
end
actor ->
actor
end
domain = NullaWeb.Endpoint.host()
with {:ok, follow_activity} <-
Activities.create_activity(%{
ap_id: follow_id,
type: "Follow",
actor: remote_actor.ap_id,
object: target_uri
}),
{:ok, accept_activity} <-
Activities.create_activity(%{
id: accept_id,
ap_id: "https://#{domain}/activities/accept/#{accept_id}",
type: "Accept",
actor: local_actor.ap_id,
object: Jason.encode!(follow_activity)
}) do
{:ok, _relation} =
case Relations.get_relation_by(%{
local_actor_id: local_actor.id,
remote_actor_id: remote_actor.id
}) do
nil ->
case Relations.create_relation(%{
local_actor_id: local_actor.id,
remote_actor_id: remote_actor.id,
followed_by: true
}) do
{:ok, relation} -> relation
{:error, changeset} -> {:error, {:relation_creation_failed, changeset}}
end
relation ->
{:ok, Relations.update_relation(relation, %{followed_by: true})}
end
Sender.send_activity(
:post,
remote_actor.inbox,
accept_activity,
local_actor.publicKey["id"],
local_actor.privateKeyPem
)
send_resp(conn, 200, "")
else
error ->
json(conn, %{"error" => "Failed to process Follow: #{error}"})
end
else
error ->
json(conn, %{"error" => "Failed to process Follow: #{error}"})
end
end
def inbox(conn, %{
"id" => _accept_id,
"type" => "Accept",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _reject_id,
"type" => "Reject",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _block_id,
"type" => "Block",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _join_id,
"type" => "Join",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _leave_id,
"type" => "Leave",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _like_id,
"type" => "Like",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _dislike_id,
"type" => "Dislike",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _announce_id,
"type" => "Announce",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, %{
"id" => _question_id,
"type" => "Question",
"actor" => _actor_uri,
"object" => _target_uri
}) do
send_resp(conn, 200, "")
end
def inbox(conn, _params) do
send_resp(conn, 400, "")
end
end