X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Factivity_pub%2Ftransmogrifier.ex;h=a37c8477fdc111f55dbeb96049d809070035001d;hb=28e8a8ab36ea0bdb8f8412cb6192b2e728a96b90;hp=2ebc526df9dda0e264041725618f32923aaae6ee;hpb=bc2668bb63aee2c42cdea48782ba5ef291c17b45;p=akkoma diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 2ebc526df..a37c8477f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -18,12 +18,30 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def get_actor(%{"actor" => actor}) when is_list(actor) do - Enum.at(actor, 0) + if is_binary(Enum.at(actor, 0)) do + Enum.at(actor, 0) + else + Enum.find(actor, fn %{"type" => type} -> type == "Person" end) + |> Map.get("id") + end + end + + def get_actor(%{"actor" => actor}) when is_map(actor) do + actor["id"] end - def get_actor(%{"actor" => actor_list}) do - Enum.find(actor_list, fn %{"type" => type} -> type == "Person" end) - |> Map.get("id") + @doc """ + Checks that an imported AP object's actor matches the domain it came from. + """ + def contain_origin(id, %{"actor" => actor} = params) do + id_uri = URI.parse(id) + actor_uri = URI.parse(get_actor(params)) + + if id_uri.host == actor_uri.host do + :ok + else + :error + end end @doc """ @@ -38,6 +56,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_emoji |> fix_tag |> fix_content_map + |> fix_likes + |> fix_addressing + end + + def fix_addressing_list(map, field) do + if is_binary(map[field]) do + map + |> Map.put(field, [map[field]]) + else + map + end + end + + def fix_addressing(map) do + map + |> fix_addressing_list("to") + |> fix_addressing_list("cc") + |> fix_addressing_list("bto") + |> fix_addressing_list("bcc") end def fix_actor(%{"attributedTo" => actor} = object) do @@ -45,8 +82,31 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("actor", get_actor(%{"actor" => actor})) end - def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object) - when not is_nil(in_reply_to_id) do + def fix_likes(%{"likes" => likes} = object) + when is_bitstring(likes) do + # Check for standardisation + # This is what Peertube does + # curl -H 'Accept: application/activity+json' $likes | jq .totalItems + object + |> Map.put("likes", []) + |> Map.put("like_count", 0) + end + + def fix_likes(object) do + object + end + + def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object) + when not is_nil(in_reply_to) do + in_reply_to_id = + if is_bitstring(in_reply_to) do + in_reply_to + else + if is_map(in_reply_to) && in_reply_to["id"] do + in_reply_to["id"] + end + end + case ActivityPub.fetch_object_from_id(in_reply_to_id) do {:ok, replied_object} -> with %Activity{} = activity <- @@ -72,13 +132,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_in_reply_to(object), do: object def fix_context(object) do + context = object["context"] || object["conversation"] || Utils.generate_context_id() + object - |> Map.put("context", object["conversation"]) + |> Map.put("context", context) + |> Map.put("conversation", context) end - def fix_attachments(object) do + def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do attachments = - (object["attachment"] || []) + attachment |> Enum.map(fn data -> url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}] Map.put(data, "url", url) @@ -88,21 +151,26 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("attachment", attachments) end - def fix_emoji(object) do - tags = object["tag"] || [] + def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do + attachment = + Map.put(attachment, "url", [ + %{"type" => "Link", "mediaType" => attachment["mediaType"], "href" => attachment["url"]} + ]) + + Map.put(object, "attachment", attachment) + end + + def fix_attachments(object) do + object + end + + def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do emoji = tags |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end) emoji = emoji |> Enum.reduce(%{}, fn data, mapping -> - name = data["name"] - - name = - if String.starts_with?(name, ":") do - name |> String.slice(1..-2) - else - name - end + name = String.trim(data["name"], ":") mapping |> Map.put(name, data["icon"]["url"]) end) @@ -114,6 +182,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("emoji", emoji) end + def fix_emoji(%{"tag" => %{"type" => "Emoji"} = tag} = object) do + name = String.trim(tag["name"], ":") + emoji = %{name => tag["icon"]["url"]} + + object + |> Map.put("emoji", emoji) + end + + def fix_emoji(object) do + object + end + def fix_tag(object) do tags = (object["tag"] || []) @@ -137,13 +217,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_content_map(object), do: object + # disallow objects with bogus IDs + def handle_incoming(%{"id" => nil}), do: :error + def handle_incoming(%{"id" => ""}), do: :error + # length of https:// = 8, should validate better, but good enough for now. + def handle_incoming(%{"id" => id}) when not (is_binary(id) and length(id) > 8), do: :error + # TODO: validate those with a Ecto scheme # - tags # - emoji def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data) - when objtype in ["Article", "Note"] do + when objtype in ["Article", "Note", "Video"] do actor = get_actor(data) - data = Map.put(data, "actor", actor) + + data = + Map.put(data, "actor", actor) + |> fix_addressing with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]), %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do @@ -292,9 +381,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def handle_incoming( - %{"type" => "Update", "object" => %{"type" => "Person"} = object, "actor" => actor_id} = + %{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} = data - ) do + ) + when object_type in ["Person", "Application", "Service", "Organization"] do with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)