Couple of fixes for groups
- Fix posts update federation and add tests - Fix posts deletion federation and add tests Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -15,6 +15,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
Config,
|
||||
Discussions,
|
||||
Events,
|
||||
Posts,
|
||||
Resources,
|
||||
Share,
|
||||
Users
|
||||
@@ -88,6 +89,7 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
{:existing, Discussions.get_discussion_by_url(url)},
|
||||
{:existing, nil} <- {:existing, Discussions.get_comment_from_url(url)},
|
||||
{:existing, nil} <- {:existing, Resources.get_resource_by_url(url)},
|
||||
{:existing, nil} <- {:existing, Posts.get_post_by_url(url)},
|
||||
{:existing, nil} <-
|
||||
{:existing, Actors.get_actor_by_url_2(url)},
|
||||
{:existing, nil} <- {:existing, Actors.get_member_by_url(url)},
|
||||
@@ -109,6 +111,9 @@ defmodule Mobilizon.Federation.ActivityPub do
|
||||
|
||||
{:error, "Gone"} ->
|
||||
{:error, "Gone", entity}
|
||||
|
||||
{:error, "Not found"} ->
|
||||
{:error, "Not found", entity}
|
||||
end
|
||||
else
|
||||
{:ok, entity}
|
||||
|
||||
@@ -50,7 +50,7 @@ defmodule Mobilizon.Federation.ActivityPub.Federator do
|
||||
|
||||
def handle(:incoming_ap_doc, params) do
|
||||
Logger.info("Handling incoming AP activity")
|
||||
Logger.debug(inspect(params))
|
||||
Logger.debug(inspect(Map.drop(params, ["@context"])))
|
||||
|
||||
case Transmogrifier.handle_incoming(params) do
|
||||
{:ok, activity, _data} ->
|
||||
|
||||
@@ -32,6 +32,10 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
|
||||
Logger.warn("Resource at #{url} is 410 Gone")
|
||||
{:error, "Gone"}
|
||||
|
||||
{:ok, %Tesla.Env{status: 404}} ->
|
||||
Logger.warn("Resource at #{url} is 404 Gone")
|
||||
{:error, "Not found"}
|
||||
|
||||
{:ok, %Tesla.Env{} = res} ->
|
||||
{:error, res}
|
||||
end
|
||||
|
||||
@@ -4,10 +4,11 @@ defmodule Mobilizon.Federation.ActivityPub.Preloader do
|
||||
"""
|
||||
|
||||
# TODO: Move me in a more appropriate place
|
||||
alias Mobilizon.{Actors, Discussions, Events, Resources}
|
||||
alias Mobilizon.{Actors, Discussions, Events, Posts, Resources}
|
||||
alias Mobilizon.Actors.{Actor, Member}
|
||||
alias Mobilizon.Discussions.{Comment, Discussion}
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Posts.Post
|
||||
alias Mobilizon.Resources.Resource
|
||||
alias Mobilizon.Tombstone
|
||||
|
||||
@@ -23,6 +24,9 @@ defmodule Mobilizon.Federation.ActivityPub.Preloader do
|
||||
def maybe_preload(%Resource{url: url}),
|
||||
do: {:ok, Resources.get_resource_by_url_with_preloads(url)}
|
||||
|
||||
def maybe_preload(%Post{url: url}),
|
||||
do: {:ok, Posts.get_post_by_url_with_preloads(url)}
|
||||
|
||||
def maybe_preload(%Actor{url: url}), do: {:ok, Actors.get_actor_by_url!(url, true)}
|
||||
|
||||
def maybe_preload(%Member{} = member), do: {:ok, member}
|
||||
|
||||
@@ -118,7 +118,9 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
|
||||
|
||||
defp process_collection(_, _), do: :error
|
||||
|
||||
defp handling_element(data) when is_map(data) do
|
||||
# If we're handling an activity
|
||||
defp handling_element(%{"type" => activity_type} = data)
|
||||
when activity_type in ["Create", "Update", "Delete"] do
|
||||
object = get_in(data, ["object"])
|
||||
|
||||
if object do
|
||||
@@ -128,6 +130,26 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
|
||||
Transmogrifier.handle_incoming(data)
|
||||
end
|
||||
|
||||
# If we're handling directly an object
|
||||
defp handling_element(data) when is_map(data) do
|
||||
object = get_in(data, ["object"])
|
||||
|
||||
if object do
|
||||
object |> Utils.get_url() |> Mobilizon.Tombstone.delete_uri_tombstone()
|
||||
end
|
||||
|
||||
activity = %{
|
||||
"type" => "Create",
|
||||
"to" => data["to"],
|
||||
"cc" => data["cc"],
|
||||
"actor" => data["actor"] || data["attributedTo"],
|
||||
"attributedTo" => data["attributedTo"] || data["actor"],
|
||||
"object" => data
|
||||
}
|
||||
|
||||
Transmogrifier.handle_incoming(activity)
|
||||
end
|
||||
|
||||
defp handling_element(uri) when is_binary(uri) do
|
||||
ActivityPub.fetch_object_from_url(uri)
|
||||
end
|
||||
|
||||
@@ -418,6 +418,50 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Update", "object" => %{"type" => "Article"} = object, "actor" => _actor} =
|
||||
update_data
|
||||
) do
|
||||
with actor <- Utils.get_actor(update_data),
|
||||
{:ok, %Actor{url: actor_url, suspended: false} = actor} <-
|
||||
ActivityPub.get_or_fetch_actor_by_url(actor),
|
||||
{:ok, %Post{} = old_post} <-
|
||||
object |> Utils.get_url() |> ActivityPub.fetch_object_from_url(),
|
||||
object_data <- Converter.Post.as_to_model_data(object),
|
||||
{:origin_check, true} <-
|
||||
{:origin_check,
|
||||
Utils.origin_check?(actor_url, update_data["object"]) ||
|
||||
Utils.activity_actor_is_group_member?(actor, old_post)},
|
||||
{:ok, %Activity{} = activity, %Post{} = new_post} <-
|
||||
ActivityPub.update(old_post, object_data, false) do
|
||||
{:ok, activity, new_post}
|
||||
else
|
||||
_e ->
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Update", "object" => %{"type" => type} = object, "actor" => _actor} =
|
||||
update_data
|
||||
)
|
||||
when type in ["ResourceCollection", "Document"] do
|
||||
with actor <- Utils.get_actor(update_data),
|
||||
{:ok, %Actor{url: actor_url, suspended: false}} <-
|
||||
ActivityPub.get_or_fetch_actor_by_url(actor),
|
||||
{:ok, %Resource{} = old_resource} <-
|
||||
object |> Utils.get_url() |> ActivityPub.fetch_object_from_url(),
|
||||
object_data <- Converter.Resource.as_to_model_data(object),
|
||||
{:origin_check, true} <- {:origin_check, Utils.origin_check?(actor_url, update_data)},
|
||||
{:ok, %Activity{} = activity, %Resource{} = new_resource} <-
|
||||
ActivityPub.update(old_resource, object_data, false) do
|
||||
{:ok, activity, new_resource}
|
||||
else
|
||||
_e ->
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Update", "object" => %{"type" => "Member"} = object, "actor" => _actor} =
|
||||
update_data
|
||||
@@ -505,7 +549,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||
with actor_url <- Utils.get_actor(data),
|
||||
{:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_actor_by_url(actor_url),
|
||||
object_id <- Utils.get_url(object),
|
||||
{:error, "Gone", object} <- ActivityPub.fetch_object_from_url(object_id, force: true),
|
||||
{:ok, object} <- can_delete_group_object(object_id),
|
||||
{:origin_check, true} <-
|
||||
{:origin_check,
|
||||
Utils.origin_check_from_id?(actor_url, object_id) ||
|
||||
@@ -975,4 +1019,25 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||
fetch_object_optionnally_authenticated(url, actor)
|
||||
end
|
||||
end
|
||||
|
||||
defp can_delete_group_object(object_id) do
|
||||
case ActivityPub.fetch_object_from_url(object_id, force: true) do
|
||||
{:error, error_message, object} when error_message in ["Gone", "Not found"] ->
|
||||
{:ok, object}
|
||||
|
||||
{:ok, %{url: url} = object} ->
|
||||
if Utils.are_same_origin?(url, Endpoint.url()),
|
||||
do: {:ok, object},
|
||||
else: {:error, "Group object URL remote"}
|
||||
|
||||
{:error, {:error, err}} ->
|
||||
{:error, err}
|
||||
|
||||
{:error, err} ->
|
||||
{:error, err}
|
||||
|
||||
err ->
|
||||
err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
@moduledoc false
|
||||
alias Mobilizon.{Actors, Posts}
|
||||
alias Mobilizon.{Actors, Posts, Tombstone}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub.Types.Entity
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
|
||||
@@ -11,6 +11,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
|
||||
@behaviour Entity
|
||||
|
||||
@public_ap "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
@impl Entity
|
||||
def create(args, additional) do
|
||||
with args <- Map.update(args, :tags, [], &ConverterUtils.fetch_tags/1),
|
||||
@@ -66,7 +68,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
def delete(
|
||||
%Post{
|
||||
url: url,
|
||||
attributed_to: %Actor{url: group_url}
|
||||
attributed_to: %Actor{url: group_url, members_url: members_url}
|
||||
} = post,
|
||||
%Actor{url: actor_url} = actor,
|
||||
_local,
|
||||
@@ -77,11 +79,13 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Posts do
|
||||
"type" => "Delete",
|
||||
"object" => Convertible.model_to_as(post),
|
||||
"id" => url <> "/delete",
|
||||
"to" => [group_url]
|
||||
"to" => [group_url, @public_ap, members_url]
|
||||
}
|
||||
|
||||
with {:ok, _post} <- Posts.delete_post(post),
|
||||
{:ok, true} <- Cachex.del(:activity_pub, "post_#{post.slug}") do
|
||||
with {:ok, %Post{} = post} <- Posts.delete_post(post),
|
||||
{:ok, true} <- Cachex.del(:activity_pub, "post_#{post.slug}"),
|
||||
{:ok, %Tombstone{} = _tombstone} <-
|
||||
Tombstone.create_tombstone(%{uri: post.url, actor_id: actor.id}) do
|
||||
{:ok, activity_data, actor, post}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -287,9 +287,14 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||
def origin_check_from_id?(id, %{"id" => other_id} = _params) when is_binary(other_id),
|
||||
do: origin_check_from_id?(id, other_id)
|
||||
|
||||
def activity_actor_is_group_member?(%Actor{id: actor_id}, object) do
|
||||
def activity_actor_is_group_member?(%Actor{id: actor_id, url: actor_url}, object) do
|
||||
Logger.debug(
|
||||
"Checking if activity actor #{actor_url} is a member from group from #{object.url}"
|
||||
)
|
||||
|
||||
case Ownable.group_actor(object) do
|
||||
%Actor{type: :Group, id: group_id} ->
|
||||
Logger.debug("Group object ID is #{group_id}")
|
||||
Actors.is_member?(actor_id, group_id)
|
||||
|
||||
_ ->
|
||||
|
||||
Reference in New Issue
Block a user