diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 60b289f08..56af34c67 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -92,14 +92,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do with ap_id <- Endpoint.url() <> conn.request_path, %Object{} = object <- Object.get_cached_by_ap_id(ap_id), user <- Map.get(assigns, :user, nil), - {_, true} <- {:visible?, Visibility.visible_for_user?(object, user)} do + {_, true} <- {:visible?, Visibility.visible_for_user?(object, user)}, + host <- maybe_get_host(Map.get(assigns, :actor_id, nil)) do conn |> maybe_skip_cache(user) |> assign(:tracking_fun_data, object.id) |> set_cache_ttl_for(object) |> put_resp_content_type("application/activity+json") |> put_view(ObjectView) - |> render("object.json", object: object) + |> render("object.json", object: object, host: host) else {:visible?, false} -> {:error, :not_found} nil -> {:error, :not_found} @@ -121,14 +122,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do %Activity{} = activity <- Activity.normalize(ap_id), {_, true} <- {:local?, activity.local}, user <- Map.get(assigns, :user, nil), - {_, true} <- {:visible?, Visibility.visible_for_user?(activity, user)} do + {_, true} <- {:visible?, Visibility.visible_for_user?(activity, user)}, + host <- maybe_get_host(Map.get(assigns, :actor_id, nil)) do conn |> maybe_skip_cache(user) |> maybe_set_tracking_data(activity) |> set_cache_ttl_for(activity) |> put_resp_content_type("application/activity+json") |> put_view(ObjectView) - |> render("object.json", object: activity) + |> render("object.json", object: activity, host: host) else {:visible?, false} -> {:error, :not_found} {:local?, false} -> {:error, :not_found} @@ -136,6 +138,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end end + defp maybe_get_host(actor_id) when is_binary(actor_id) do + %{host: host} = URI.parse(actor_id) + + host + end + + defp maybe_get_host(_), do: nil + defp maybe_set_tracking_data(conn, %Activity{data: %{"type" => "Create"}} = activity) do object_id = Object.normalize(activity, fetch: false).id assign(conn, :tracking_fun_data, object_id) diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 0de3a0d43..3fd0d1316 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -89,9 +89,9 @@ defmodule Pleroma.Web.ActivityPub.Publisher do ap_id = activity.data["id"] Logger.debug("Federating #{ap_id} to #{inbox}") - uri = %{path: path} = URI.parse(inbox) + uri = %{host: host, path: path} = URI.parse(inbox) - {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data, host) cc = Map.get(params, :cc, []) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 69e6a63a7..44e221fd7 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -723,7 +723,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do defp set_voters_count(obj), do: obj # Prepares the object of an outgoing create activity. - def prepare_object(object) do + def prepare_object(object, host \\ nil) do object |> add_hashtags |> add_mention_tags @@ -738,15 +738,21 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> strip_internal_fields |> strip_internal_tags |> set_type - |> maybe_process_history + |> maybe_process_history(host) + |> patch_object(host) end - defp maybe_process_history(%{"formerRepresentations" => %{"orderedItems" => history}} = object) do + defp maybe_process_history(object, host) + + defp maybe_process_history( + %{"formerRepresentations" => %{"orderedItems" => history}} = object, + host + ) do processed_history = Enum.map( history, fn - item when is_map(item) -> prepare_object(item) + item when is_map(item) -> prepare_object(item, host) item -> item end ) @@ -754,7 +760,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do put_in(object, ["formerRepresentations", "orderedItems"], processed_history) end - defp maybe_process_history(object) do + defp maybe_process_history(object, _host) do object end @@ -763,7 +769,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # internal -> Mastodon # """ - def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data) + def prepare_outgoing(data, host \\ nil) + + def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data, host) when activity_type in ["Create", "Listen"] do object = object_id @@ -772,32 +780,38 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data - |> Map.put("object", prepare_object(object)) + |> Map.put("object", prepare_object(object, host)) |> Map.merge(Utils.make_json_ld_header(object)) |> Map.delete("bcc") {:ok, data} end - def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) + def prepare_outgoing( + %{"type" => "Update", "object" => %{"type" => objtype} = object} = data, + host + ) when objtype in Pleroma.Constants.updatable_object_types() do data = data - |> Map.put("object", prepare_object(object)) + |> Map.put("object", prepare_object(object, host)) |> Map.merge(Utils.make_json_ld_header(object)) |> Map.delete("bcc") {:ok, data} end - def prepare_outgoing(%{"type" => "Announce", "actor" => ap_id, "object" => object_id} = data) do + def prepare_outgoing( + %{"type" => "Announce", "actor" => ap_id, "object" => object_id} = data, + host + ) do object = object_id |> Object.normalize(fetch: false) data = if Visibility.private?(object) && object.data["actor"] == ap_id do - data |> Map.put("object", object |> Map.get(:data) |> prepare_object) + data |> Map.put("object", object |> Map.get(:data) |> prepare_object(host)) else data |> maybe_fix_object_url end @@ -813,7 +827,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # Mastodon Accept/Reject requires a non-normalized object containing the actor URIs, # because of course it does. - def prepare_outgoing(%{"type" => "Accept"} = data) do + def prepare_outgoing(%{"type" => "Accept"} = data, _host) do with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, @@ -831,7 +845,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end - def prepare_outgoing(%{"type" => "Reject"} = data) do + def prepare_outgoing(%{"type" => "Reject"} = data, _host) do with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, @@ -849,7 +863,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end - def prepare_outgoing(%{"type" => _type} = data) do + def prepare_outgoing(%{"type" => _type} = data, _host) do data = data |> strip_internal_fields @@ -1000,4 +1014,39 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def maybe_fix_user_url(data), do: data def maybe_fix_user_object(data), do: maybe_fix_user_url(data) + + defp patch_object(nil, _host), do: nil + + defp patch_object(object, nil), do: object + + defp patch_object(object, host) do + object + |> update_if_exists("source", &patch_object(&1, host)) + |> update_if_exists("content", &replace_instance_host(&1, host)) + |> patch_content_map(host) + end + + defp patch_content_map(%{"contentMap" => %{} = content_map}, host) do + content_map + |> Enum.map(fn {key, value} -> {key, replace_instance_host(value, host)} end) + |> Map.new() + end + + defp patch_content_map(content_map, _host), do: content_map + + defp replace_instance_host(content, host) when is_binary(content) and is_binary(host) do + content + |> String.replace("$INSTANCE$host$", host) + end + + defp replace_instance_host(content, _), do: content + + defp update_if_exists(map, key, func) do + if Map.has_key?(map, key) do + value = Map.get(map, key) + Map.put(map, key, func.(value)) + else + map + end + end end diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 13b5b2542..9b716a3f3 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -8,31 +8,34 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do alias Pleroma.Object alias Pleroma.Web.ActivityPub.Transmogrifier - def render("object.json", %{object: %Object{} = object}) do + def render("object.json", %{object: %Object{} = object, host: host}) do base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(object.data) - additional = Transmogrifier.prepare_object(object.data) + additional = Transmogrifier.prepare_object(object.data, host) Map.merge(base, additional) end - def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity}) + def render("object.json", %{ + object: %Activity{data: %{"type" => activity_type}} = activity, + host: host + }) when activity_type in ["Create", "Listen"] do base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data) object = Object.normalize(activity, fetch: false) additional = Transmogrifier.prepare_object(activity.data) - |> Map.put("object", Transmogrifier.prepare_object(object.data)) + |> Map.put("object", Transmogrifier.prepare_object(object.data, host)) Map.merge(base, additional) end - def render("object.json", %{object: %Activity{} = activity}) do + def render("object.json", %{object: %Activity{} = activity, host: host}) do base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data) object_id = Object.normalize(activity, id_only: true) additional = - Transmogrifier.prepare_object(activity.data) + Transmogrifier.prepare_object(activity.data, host) |> Map.put("object", object_id) Map.merge(base, additional) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 1261ba4cf..fbc09cd0d 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -269,7 +269,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do pinned_objects |> Enum.sort_by(fn {_, pinned_at} -> pinned_at end, &>=/2) |> Enum.map(fn {id, _} -> - ObjectView.render("object.json", %{object: Object.get_cached_by_ap_id(id)}) + ObjectView.render("object.json", %{object: Object.get_cached_by_ap_id(id), host: nil}) end) %{