Merge branch 'develop' into paradedb-search-backend
This commit is contained in:
commit
3c916891f6
39 changed files with 1782 additions and 103 deletions
|
|
@ -15,12 +15,28 @@ defmodule Pleroma.Object.Containment do
|
|||
actor
|
||||
end
|
||||
|
||||
def get_actor(%{"actor" => nil, "attributedTo" => actor}) when not is_nil(actor) do
|
||||
get_actor(%{"actor" => actor})
|
||||
end
|
||||
|
||||
def get_actor(%{"actor" => nil}), do: nil
|
||||
|
||||
def get_actor(%{"actor" => []}), do: nil
|
||||
|
||||
def get_actor(%{"actor" => actor}) when is_list(actor) do
|
||||
if is_binary(Enum.at(actor, 0)) do
|
||||
Enum.at(actor, 0)
|
||||
else
|
||||
Enum.find(actor, fn %{"type" => type} -> type in ["Person", "Service", "Application"] end)
|
||||
|> Map.get("id")
|
||||
case actor do
|
||||
[first | _] when is_binary(first) ->
|
||||
first
|
||||
|
||||
_ ->
|
||||
Enum.find_value(actor, fn
|
||||
%{"type" => type, "id" => id}
|
||||
when type in ["Person", "Service", "Application"] and is_binary(id) ->
|
||||
id
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -28,10 +44,6 @@ defmodule Pleroma.Object.Containment do
|
|||
id
|
||||
end
|
||||
|
||||
def get_actor(%{"actor" => nil, "attributedTo" => actor}) when not is_nil(actor) do
|
||||
get_actor(%{"actor" => actor})
|
||||
end
|
||||
|
||||
def get_object(%{"object" => id}) when is_binary(id) do
|
||||
id
|
||||
end
|
||||
|
|
@ -67,9 +79,11 @@ defmodule Pleroma.Object.Containment do
|
|||
|
||||
def contain_origin(id, %{"actor" => _actor} = params) do
|
||||
id_uri = URI.parse(id)
|
||||
actor_uri = URI.parse(get_actor(params))
|
||||
|
||||
compare_uris(actor_uri, id_uri)
|
||||
case get_actor(params) do
|
||||
actor when is_binary(actor) -> compare_uris(URI.parse(actor), id_uri)
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def contain_origin(id, %{"attributedTo" => actor} = params),
|
||||
|
|
|
|||
|
|
@ -309,7 +309,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
} = conn,
|
||||
%{"nickname" => nickname} = params
|
||||
) do
|
||||
with {:recipient_exists, %User{} = recipient} <-
|
||||
with false <- unsupported_http_message_signature?(conn),
|
||||
{:recipient_exists, %User{} = recipient} <-
|
||||
{:recipient_exists, User.get_cached_by_nickname(nickname)},
|
||||
{:sender_exists, {:ok, %User{} = actor}} <-
|
||||
{:sender_exists, User.get_or_fetch_by_ap_id(params["actor"])},
|
||||
|
|
@ -320,6 +321,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
Federator.incoming_ap_doc(params)
|
||||
json(conn, "ok")
|
||||
else
|
||||
true ->
|
||||
reject_unsupported_http_message_signature(conn)
|
||||
|
||||
{:recipient_exists, _} ->
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|
|
@ -348,20 +352,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
end
|
||||
|
||||
def inbox(%{assigns: %{valid_signature: true, valid_host_header: true}} = conn, params) do
|
||||
Federator.incoming_ap_doc(params)
|
||||
json(conn, "ok")
|
||||
if unsupported_http_message_signature?(conn) do
|
||||
reject_unsupported_http_message_signature(conn)
|
||||
else
|
||||
Federator.incoming_ap_doc(params)
|
||||
json(conn, "ok")
|
||||
end
|
||||
end
|
||||
|
||||
def inbox(%{assigns: %{valid_signature: false}} = conn, params) do
|
||||
Federator.incoming_failed_signature_ap_doc(%{
|
||||
method: conn.method,
|
||||
req_headers: conn.req_headers,
|
||||
request_path: conn.request_path,
|
||||
params: params,
|
||||
query_string: conn.query_string
|
||||
})
|
||||
if unsupported_http_message_signature?(conn) do
|
||||
reject_unsupported_http_message_signature(conn)
|
||||
else
|
||||
Federator.incoming_failed_signature_ap_doc(%{
|
||||
method: conn.method,
|
||||
req_headers: conn.req_headers,
|
||||
request_path: conn.request_path,
|
||||
params: params,
|
||||
query_string: conn.query_string
|
||||
})
|
||||
|
||||
json(conn, "ok")
|
||||
json(conn, "ok")
|
||||
end
|
||||
end
|
||||
|
||||
# POST /relay/inbox -or- POST /internal/fetch/inbox
|
||||
|
|
@ -381,6 +393,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|> json("error, missing HTTP Signature")
|
||||
end
|
||||
|
||||
defp reject_unsupported_http_message_signature(conn) do
|
||||
conn
|
||||
|> put_status(:unauthorized)
|
||||
|> json("error, unsupported HTTP Message Signature")
|
||||
end
|
||||
|
||||
defp unsupported_http_message_signature?(conn) do
|
||||
signature_headers = Plug.Conn.get_req_header(conn, "signature")
|
||||
|
||||
multiple_signature_headers?(signature_headers) or
|
||||
(Plug.Conn.get_req_header(conn, "signature-input") != [] and
|
||||
not cavage_signature?(signature_headers))
|
||||
end
|
||||
|
||||
defp multiple_signature_headers?([_, _ | _]), do: true
|
||||
defp multiple_signature_headers?(_), do: false
|
||||
|
||||
defp cavage_signature?(signature_headers) do
|
||||
Enum.any?(signature_headers, &Regex.match?(~r/(^|,)\s*keyId\s*=/, &1))
|
||||
end
|
||||
|
||||
defp post_inbox_relayed_create(conn, params) do
|
||||
Logger.debug(
|
||||
"Signature missing or not from author, relayed Create message, fetching object from source"
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
|
||||
with {:ok, object_data} <-
|
||||
object
|
||||
|> CommonFixes.maybe_set_attributed_to_from_activity(create_activity)
|
||||
|> CommonFixes.maybe_add_language_from_activity(create_activity)
|
||||
|> cast_and_apply_and_stringify_with_history(),
|
||||
meta = Keyword.put(meta, :object_data, object_data),
|
||||
|
|
@ -172,6 +173,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
{_, {:ok, object_data, _}} <-
|
||||
{:object_validation,
|
||||
object
|
||||
|> CommonFixes.maybe_set_attributed_to_from_activity(update_activity)
|
||||
|> CommonFixes.maybe_add_language_from_activity(update_activity)
|
||||
|> validate(meta)},
|
||||
meta = Keyword.put(meta, :object_data, object_data),
|
||||
|
|
|
|||
|
|
@ -50,7 +50,32 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|
|||
end
|
||||
|
||||
defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data
|
||||
defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"])
|
||||
|
||||
defp fix_url(%{"url" => url} = data) when is_map(url) do
|
||||
if is_binary(url["href"]) do
|
||||
Map.put(data, "url", url["href"])
|
||||
else
|
||||
Map.delete(data, "url")
|
||||
end
|
||||
end
|
||||
|
||||
defp fix_url(%{"url" => url} = data) when is_list(url) do
|
||||
first_element = Enum.at(url, 0)
|
||||
|
||||
url_string =
|
||||
cond do
|
||||
is_bitstring(first_element) -> first_element
|
||||
is_map(first_element) -> first_element["href"]
|
||||
true -> nil
|
||||
end
|
||||
|
||||
if is_binary(url_string) do
|
||||
Map.put(data, "url", url_string)
|
||||
else
|
||||
Map.delete(data, "url")
|
||||
end
|
||||
end
|
||||
|
||||
defp fix_url(data), do: data
|
||||
|
||||
defp fix_tag(%{"tag" => tag} = data) when is_list(tag) do
|
||||
|
|
@ -79,10 +104,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|
|||
|
||||
defp fix_replies(data), do: Map.delete(data, "replies")
|
||||
|
||||
def fix_attachments(%{"attachment" => attachment} = data) when is_map(attachment),
|
||||
do: Map.put(data, "attachment", [attachment])
|
||||
|
||||
def fix_attachments(data), do: data
|
||||
def fix_attachments(data), do: Transmogrifier.fix_attachments(data)
|
||||
|
||||
defp remote_mention_resolver(
|
||||
%{"id" => ap_id, "tag" => tags},
|
||||
|
|
|
|||
|
|
@ -41,22 +41,34 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
def fix_object_defaults(data) do
|
||||
data = Maps.filter_empty_values(data)
|
||||
|
||||
in_reply_to_id = in_reply_to_id(data["inReplyTo"])
|
||||
|
||||
context =
|
||||
Utils.maybe_create_context(
|
||||
data["context"] || data["conversation"] || data["inReplyTo"] || data["id"]
|
||||
data["context"] || data["conversation"] || in_reply_to_id || data["id"]
|
||||
)
|
||||
|
||||
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"])
|
||||
data = Map.put(data, "context", context)
|
||||
|
||||
data
|
||||
|> Map.put("context", context)
|
||||
|> cast_and_filter_recipients("to", follower_collection)
|
||||
|> cast_and_filter_recipients("cc", follower_collection)
|
||||
|> cast_and_filter_recipients("bto", follower_collection)
|
||||
|> cast_and_filter_recipients("bcc", follower_collection)
|
||||
|> Transmogrifier.fix_implicit_addressing(follower_collection)
|
||||
with attributed_to when is_binary(attributed_to) <- data["attributedTo"],
|
||||
%User{follower_address: follower_collection} <- User.get_cached_by_ap_id(attributed_to) do
|
||||
data
|
||||
|> cast_and_filter_recipients("to", follower_collection)
|
||||
|> cast_and_filter_recipients("cc", follower_collection)
|
||||
|> cast_and_filter_recipients("bto", follower_collection)
|
||||
|> cast_and_filter_recipients("bcc", follower_collection)
|
||||
|> Transmogrifier.fix_implicit_addressing(follower_collection)
|
||||
else
|
||||
_ -> data
|
||||
end
|
||||
end
|
||||
|
||||
defp in_reply_to_id(in_reply_to) when is_binary(in_reply_to), do: in_reply_to
|
||||
defp in_reply_to_id(%{"id" => in_reply_to}) when is_binary(in_reply_to), do: in_reply_to
|
||||
defp in_reply_to_id(%{"href" => in_reply_to}) when is_binary(in_reply_to), do: in_reply_to
|
||||
defp in_reply_to_id([in_reply_to | _]), do: in_reply_to_id(in_reply_to)
|
||||
defp in_reply_to_id(_), do: nil
|
||||
|
||||
def fix_activity_addressing(activity) do
|
||||
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"])
|
||||
|
||||
|
|
@ -79,6 +91,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
|> Map.put("attributedTo", actor)
|
||||
end
|
||||
|
||||
def maybe_set_attributed_to_from_activity(object, activity) when is_map(object) do
|
||||
if is_nil(object["attributedTo"]) and is_nil(object["actor"]) do
|
||||
case Containment.get_actor(activity) do
|
||||
actor when is_binary(actor) -> Map.put(object, "attributedTo", actor)
|
||||
_ -> object
|
||||
end
|
||||
else
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
def fix_activity_context(data, %Object{data: %{"context" => object_context}}) do
|
||||
data
|
||||
|> Map.put("context", object_context)
|
||||
|
|
@ -96,23 +119,37 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
Map.put(data, "to", to)
|
||||
end
|
||||
|
||||
def fix_quote_url(%{"quoteUrl" => _quote_url} = data), do: data
|
||||
def fix_quote_url(%{"quoteUrl" => quote_url} = data) do
|
||||
case normalize_object_id(quote_url) do
|
||||
quote_url when is_binary(quote_url) -> Map.put(data, "quoteUrl", quote_url)
|
||||
_ -> Map.delete(data, "quoteUrl")
|
||||
end
|
||||
end
|
||||
|
||||
# Fedibird
|
||||
# https://github.com/fedibird/mastodon/commit/dbd7ae6cf58a92ec67c512296b4daaea0d01e6ac
|
||||
def fix_quote_url(%{"quoteUri" => quote_url} = data) do
|
||||
Map.put(data, "quoteUrl", quote_url)
|
||||
case normalize_object_id(quote_url) do
|
||||
quote_url when is_binary(quote_url) -> Map.put(data, "quoteUrl", quote_url)
|
||||
_ -> data
|
||||
end
|
||||
end
|
||||
|
||||
# Old Fedibird (bug)
|
||||
# https://github.com/fedibird/mastodon/issues/9
|
||||
def fix_quote_url(%{"quoteURL" => quote_url} = data) do
|
||||
Map.put(data, "quoteUrl", quote_url)
|
||||
case normalize_object_id(quote_url) do
|
||||
quote_url when is_binary(quote_url) -> Map.put(data, "quoteUrl", quote_url)
|
||||
_ -> data
|
||||
end
|
||||
end
|
||||
|
||||
# Misskey fallback
|
||||
def fix_quote_url(%{"_misskey_quote" => quote_url} = data) do
|
||||
Map.put(data, "quoteUrl", quote_url)
|
||||
case normalize_object_id(quote_url) do
|
||||
quote_url when is_binary(quote_url) -> Map.put(data, "quoteUrl", quote_url)
|
||||
_ -> data
|
||||
end
|
||||
end
|
||||
|
||||
def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do
|
||||
|
|
@ -128,6 +165,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
|
||||
def fix_quote_url(data), do: data
|
||||
|
||||
defp normalize_object_id(object_id) when is_binary(object_id), do: object_id
|
||||
defp normalize_object_id(%{"id" => object_id}) when is_binary(object_id), do: object_id
|
||||
defp normalize_object_id([object_id | _]) when is_binary(object_id), do: object_id
|
||||
defp normalize_object_id(_), do: nil
|
||||
|
||||
# On Mastodon, `"likes"` attribute includes an inlined `Collection` with `totalItems`,
|
||||
# not a list of users.
|
||||
# https://github.com/mastodon/mastodon/pull/32007
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|
|||
require Pleroma.Constants
|
||||
|
||||
@primary_key false
|
||||
@tag_types ~w[Mention Hashtag Emoji Link]
|
||||
|
||||
embedded_schema do
|
||||
# Common
|
||||
field(:type, :string)
|
||||
|
|
@ -49,7 +51,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|
|||
|> validate_required([:type, :href])
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => "Hashtag", "name" => name} = data) do
|
||||
def changeset(struct, %{"type" => "Hashtag", "name" => name} = data) when is_binary(name) do
|
||||
name = String.downcase(name)
|
||||
data = Map.put(data, "name", name)
|
||||
|
||||
|
|
@ -58,13 +60,42 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|
|||
|> validate_required([:type, :name])
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => "Emoji"} = data) do
|
||||
data = Map.put(data, "name", String.trim(data["name"], ":"))
|
||||
|
||||
def changeset(struct, %{"type" => "Hashtag"} = data) do
|
||||
struct
|
||||
|> cast(data, [:type, :name, :updated, :id])
|
||||
|> cast_embed(:icon, with: &icon_changeset/2)
|
||||
|> validate_required([:type, :name, :icon])
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => "Emoji", "name" => name} = data) when is_binary(name) do
|
||||
data =
|
||||
data
|
||||
|> Map.put("name", String.trim(data["name"], ":"))
|
||||
|> normalize_emoji_icon()
|
||||
|
||||
case data["icon"] do
|
||||
%{"url" => url} when is_binary(url) ->
|
||||
if valid_http_url?(url) do
|
||||
struct
|
||||
|> cast(data, [:type, :name, :updated, :id])
|
||||
|> cast_embed(:icon, with: &icon_changeset/2)
|
||||
|> validate_required([:type, :name, :icon])
|
||||
else
|
||||
struct
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
|
||||
_ ->
|
||||
struct
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => "Emoji"} = data) do
|
||||
struct
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => "Link"} = data) do
|
||||
|
|
@ -74,12 +105,80 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|
|||
|> validate_required([:type, :href, :mediaType])
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => types} = data) when is_list(types) do
|
||||
changeset(struct, infer_type(data))
|
||||
end
|
||||
|
||||
def changeset(struct, %{"type" => _} = data) do
|
||||
struct
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
|
||||
def changeset(struct, data) when is_map(data) do
|
||||
data = normalize(data)
|
||||
|
||||
if Map.has_key?(data, "type") do
|
||||
changeset(struct, data)
|
||||
else
|
||||
struct
|
||||
|> cast(data, [])
|
||||
|> Map.put(:action, :ignore)
|
||||
end
|
||||
end
|
||||
|
||||
def normalize(data) when is_map(data), do: infer_type(data)
|
||||
|
||||
defp infer_type(%{"type" => types} = data) when is_list(types) do
|
||||
type = Enum.find(types, &(&1 in @tag_types)) || Enum.find(types, &is_binary/1)
|
||||
|
||||
if type, do: Map.put(data, "type", type), else: Map.delete(data, "type")
|
||||
end
|
||||
|
||||
defp infer_type(%{"type" => _} = data), do: data
|
||||
defp infer_type(%{"name" => "#" <> _} = data), do: Map.put(data, "type", "Hashtag")
|
||||
defp infer_type(%{"name" => "@" <> _} = data), do: Map.put(data, "type", "Mention")
|
||||
|
||||
defp infer_type(%{"mediaType" => _media_type, "href" => _href} = data),
|
||||
do: Map.put(data, "type", "Link")
|
||||
|
||||
defp infer_type(data), do: data
|
||||
|
||||
defp normalize_emoji_icon(%{"icon" => icon} = data) when is_binary(icon) do
|
||||
Map.put(data, "icon", %{"type" => "Image", "url" => icon})
|
||||
end
|
||||
|
||||
defp normalize_emoji_icon(%{"icon" => icon} = data) when is_map(icon) do
|
||||
case extract_icon_url(icon) do
|
||||
url when is_binary(url) -> Map.put(data, "icon", %{"type" => "Image", "url" => url})
|
||||
_ -> Map.delete(data, "icon")
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_emoji_icon(data), do: data
|
||||
|
||||
defp extract_icon_url(%{"url" => url}) when is_binary(url), do: url
|
||||
|
||||
defp extract_icon_url(%{"url" => %{"href" => href}}) when is_binary(href), do: href
|
||||
|
||||
defp extract_icon_url(%{"url" => [first | _]}) do
|
||||
cond do
|
||||
is_binary(first) -> first
|
||||
is_map(first) -> first["href"]
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_icon_url(%{"href" => href}) when is_binary(href), do: href
|
||||
|
||||
defp extract_icon_url(_), do: nil
|
||||
|
||||
defp valid_http_url?(url) when is_binary(url) do
|
||||
match?({:ok, _}, ObjectValidators.Uri.cast(url))
|
||||
end
|
||||
|
||||
defp valid_http_url?(_), do: false
|
||||
|
||||
def icon_changeset(struct, data) do
|
||||
struct
|
||||
|> cast(data, [:type, :url])
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
alias Pleroma.Web.ActivityPub.Builder
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidator
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
||||
alias Pleroma.Web.ActivityPub.Pipeline
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
|
@ -28,6 +29,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
require Pleroma.Constants
|
||||
|
||||
@supported_types Pleroma.Constants.activity_types() ++
|
||||
Pleroma.Constants.object_types() ++ Pleroma.Constants.actor_types()
|
||||
|
||||
@doc """
|
||||
Modifies an incoming AP object (mastodon format) to our internal format.
|
||||
"""
|
||||
|
|
@ -201,9 +205,29 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
|
||||
when not is_nil(in_reply_to) do
|
||||
in_reply_to_id = prepare_in_reply_to(in_reply_to)
|
||||
|
||||
object =
|
||||
cond do
|
||||
is_list(in_reply_to) ->
|
||||
if not_empty_string(in_reply_to_id) do
|
||||
Map.put(object, "inReplyTo", in_reply_to_id)
|
||||
else
|
||||
Map.delete(object, "inReplyTo")
|
||||
end
|
||||
|
||||
is_map(in_reply_to) and is_nil(in_reply_to["id"]) and is_binary(in_reply_to["href"]) ->
|
||||
Map.put(object, "inReplyTo", in_reply_to["href"])
|
||||
|
||||
is_map(in_reply_to) and is_nil(in_reply_to["id"]) and is_nil(in_reply_to["href"]) ->
|
||||
Map.delete(object, "inReplyTo")
|
||||
|
||||
true ->
|
||||
object
|
||||
end
|
||||
|
||||
depth = (options[:depth] || 0) + 1
|
||||
|
||||
if Federator.allowed_thread_distance?(depth) do
|
||||
if not_empty_string(in_reply_to_id) and Federator.allowed_thread_distance?(depth) do
|
||||
with {:ok, replied_object} <- get_obj_helper(in_reply_to_id, options),
|
||||
%Activity{} <- Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
|
||||
object
|
||||
|
|
@ -249,9 +273,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) ->
|
||||
in_reply_to["id"]
|
||||
|
||||
is_map(in_reply_to) && is_bitstring(in_reply_to["href"]) ->
|
||||
in_reply_to["href"]
|
||||
|
||||
is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) ->
|
||||
Enum.at(in_reply_to, 0)
|
||||
|
||||
is_list(in_reply_to) && is_map(Enum.at(in_reply_to, 0)) ->
|
||||
in_reply_to
|
||||
|> Enum.at(0)
|
||||
|> prepare_in_reply_to()
|
||||
|
||||
true ->
|
||||
""
|
||||
end
|
||||
|
|
@ -265,59 +297,74 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> Map.drop(["conversation"])
|
||||
end
|
||||
|
||||
defp valid_http_url?(href) when is_binary(href) do
|
||||
match?({:ok, _}, ObjectValidators.Uri.cast(href))
|
||||
end
|
||||
|
||||
defp valid_http_url?(_), do: false
|
||||
|
||||
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
|
||||
attachments =
|
||||
Enum.map(attachment, fn data ->
|
||||
url =
|
||||
cond do
|
||||
is_list(data["url"]) -> List.first(data["url"])
|
||||
is_map(data["url"]) -> data["url"]
|
||||
true -> nil
|
||||
end
|
||||
Enum.map(attachment, fn
|
||||
data when is_map(data) ->
|
||||
url =
|
||||
cond do
|
||||
is_list(data["url"]) -> List.first(data["url"])
|
||||
is_map(data["url"]) -> data["url"]
|
||||
true -> nil
|
||||
end
|
||||
|
||||
media_type =
|
||||
cond do
|
||||
is_map(url) && url =~ Pleroma.Constants.mime_regex() ->
|
||||
url["mediaType"]
|
||||
url_data = if is_map(url), do: url, else: %{}
|
||||
|
||||
is_bitstring(data["mediaType"]) && data["mediaType"] =~ Pleroma.Constants.mime_regex() ->
|
||||
data["mediaType"]
|
||||
media_type =
|
||||
cond do
|
||||
is_bitstring(url_data["mediaType"]) &&
|
||||
url_data["mediaType"] =~ Pleroma.Constants.mime_regex() ->
|
||||
url_data["mediaType"]
|
||||
|
||||
is_bitstring(data["mimeType"]) && data["mimeType"] =~ Pleroma.Constants.mime_regex() ->
|
||||
data["mimeType"]
|
||||
is_bitstring(data["mediaType"]) &&
|
||||
data["mediaType"] =~ Pleroma.Constants.mime_regex() ->
|
||||
data["mediaType"]
|
||||
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
is_bitstring(data["mimeType"]) && data["mimeType"] =~ Pleroma.Constants.mime_regex() ->
|
||||
data["mimeType"]
|
||||
|
||||
href =
|
||||
cond do
|
||||
is_map(url) && is_binary(url["href"]) -> url["href"]
|
||||
is_binary(data["url"]) -> data["url"]
|
||||
is_binary(data["href"]) -> data["href"]
|
||||
true -> nil
|
||||
end
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
|
||||
href =
|
||||
cond do
|
||||
is_binary(url) -> url
|
||||
is_binary(url_data["href"]) -> url_data["href"]
|
||||
is_binary(data["url"]) -> data["url"]
|
||||
is_binary(data["href"]) -> data["href"]
|
||||
true -> nil
|
||||
end
|
||||
|
||||
if href && valid_http_url?(href) do
|
||||
attachment_url =
|
||||
%{
|
||||
"href" => href,
|
||||
"type" => Map.get(url_data, "type", "Link")
|
||||
}
|
||||
|> Maps.put_if_present("mediaType", media_type)
|
||||
|> Maps.put_if_present("width", url_data["width"] || data["width"])
|
||||
|> Maps.put_if_present("height", url_data["height"] || data["height"])
|
||||
|
||||
if href do
|
||||
attachment_url =
|
||||
%{
|
||||
"href" => href,
|
||||
"type" => Map.get(url || %{}, "type", "Link")
|
||||
"url" => [attachment_url],
|
||||
"type" => data["type"] || "Document"
|
||||
}
|
||||
|> Maps.put_if_present("mediaType", media_type)
|
||||
|> Maps.put_if_present("width", (url || %{})["width"] || data["width"])
|
||||
|> Maps.put_if_present("height", (url || %{})["height"] || data["height"])
|
||||
|> Maps.put_if_present("name", data["name"])
|
||||
|> Maps.put_if_present("blurhash", data["blurhash"])
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
%{
|
||||
"url" => [attachment_url],
|
||||
"type" => data["type"] || "Document"
|
||||
}
|
||||
|> Maps.put_if_present("mediaType", media_type)
|
||||
|> Maps.put_if_present("name", data["name"])
|
||||
|> Maps.put_if_present("blurhash", data["blurhash"])
|
||||
else
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end)
|
||||
|> Enum.filter(& &1)
|
||||
|
||||
|
|
@ -351,24 +398,58 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def fix_url(object), do: object
|
||||
|
||||
defp emoji_icon_url(icon) when is_binary(icon), do: icon
|
||||
|
||||
defp emoji_icon_url(%{"url" => url}) when is_binary(url), do: url
|
||||
|
||||
defp emoji_icon_url(%{"url" => %{"href" => href}}) when is_binary(href), do: href
|
||||
|
||||
defp emoji_icon_url(%{"url" => [first | _]}) do
|
||||
cond do
|
||||
is_binary(first) -> first
|
||||
is_map(first) -> first["href"] || first["url"] || first["id"]
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp emoji_icon_url(%{"href" => href}) when is_binary(href), do: href
|
||||
|
||||
defp emoji_icon_url(_), do: nil
|
||||
|
||||
defp valid_emoji_icon_url(icon) do
|
||||
case emoji_icon_url(icon) do
|
||||
url when is_binary(url) -> if valid_http_url?(url), do: url
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do
|
||||
emoji =
|
||||
tags
|
||||
|> Enum.filter(fn data -> is_map(data) and data["type"] == "Emoji" and data["icon"] end)
|
||||
|> Enum.filter(fn data ->
|
||||
is_map(data) and data["type"] == "Emoji" and is_binary(data["name"]) and data["icon"]
|
||||
end)
|
||||
|> Enum.reduce(%{}, fn data, mapping ->
|
||||
name = String.trim(data["name"], ":")
|
||||
|
||||
Map.put(mapping, name, data["icon"]["url"])
|
||||
case valid_emoji_icon_url(data["icon"]) do
|
||||
url when is_binary(url) -> Map.put(mapping, name, url)
|
||||
_ -> mapping
|
||||
end
|
||||
end)
|
||||
|
||||
Map.put(object, "emoji", emoji)
|
||||
end
|
||||
|
||||
def fix_emoji(%{"tag" => %{"type" => "Emoji"} = tag} = object) do
|
||||
name = String.trim(tag["name"], ":")
|
||||
emoji = %{name => tag["icon"]["url"]}
|
||||
def fix_emoji(%{"tag" => %{"type" => "Emoji", "name" => name} = tag} = object)
|
||||
when is_binary(name) do
|
||||
name = String.trim(name, ":")
|
||||
|
||||
Map.put(object, "emoji", emoji)
|
||||
with url when is_binary(url) <- valid_emoji_icon_url(tag["icon"]) do
|
||||
Map.put(object, "emoji", %{name => url})
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
end
|
||||
|
||||
def fix_emoji(object), do: object
|
||||
|
|
@ -376,7 +457,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def fix_tag(%{"tag" => tag} = object) when is_list(tag) do
|
||||
tags =
|
||||
tag
|
||||
|> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
|
||||
|> Enum.filter(fn data ->
|
||||
is_map(data) and data["type"] == "Hashtag" and is_binary(data["name"])
|
||||
end)
|
||||
|> Enum.map(fn
|
||||
%{"name" => "#" <> hashtag} -> String.downcase(hashtag)
|
||||
%{"name" => hashtag} -> String.downcase(hashtag)
|
||||
|
|
@ -439,9 +522,37 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def handle_incoming(data, options \\ []) do
|
||||
data
|
||||
|> fix_recursive(&strip_internal_fields/1)
|
||||
|> fix_recursive(&fix_type_as_string/1)
|
||||
|> handle_incoming_normalized(options)
|
||||
end
|
||||
|
||||
defp fix_type_as_string(data) do
|
||||
data
|
||||
|> normalize_type()
|
||||
|> normalize_tag_types()
|
||||
end
|
||||
|
||||
defp normalize_type(%{"type" => types} = data) when is_list(types) do
|
||||
type = Enum.find(types, &(&1 in @supported_types)) || Enum.find(types, &is_binary/1)
|
||||
|
||||
if type, do: Map.put(data, "type", type), else: data
|
||||
end
|
||||
|
||||
defp normalize_type(data), do: data
|
||||
|
||||
defp normalize_tag_types(%{"tag" => tags} = data) when is_list(tags) do
|
||||
Map.put(data, "tag", Enum.map(tags, &normalize_tag_type/1))
|
||||
end
|
||||
|
||||
defp normalize_tag_types(%{"tag" => tag} = data) when is_map(tag) do
|
||||
Map.put(data, "tag", normalize_tag_type(tag))
|
||||
end
|
||||
|
||||
defp normalize_tag_types(data), do: data
|
||||
|
||||
defp normalize_tag_type(tag) when is_map(tag), do: TagValidator.normalize(tag)
|
||||
defp normalize_tag_type(tag), do: tag
|
||||
|
||||
# Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
|
||||
# with nil ID.
|
||||
defp handle_incoming_normalized(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue