# Pleroma: A lightweight social networking server # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus.OStatusController do use Pleroma.Web, :controller alias Fallback.RedirectController alias Pleroma.Activity alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Federator alias Pleroma.Web.Metadata.PlayerView alias Pleroma.Web.OStatus.ActivityRepresenter alias Pleroma.Web.Router alias Pleroma.Web.XML plug( Pleroma.Plugs.RateLimiter, {:ap_routes, params: ["uuid"]} when action in [:object, :activity] ) plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming]) plug( Pleroma.Plugs.SetFormatPlug when action in [:object, :activity, :notice] ) action_fallback(:errors) defp decode_or_retry(body) do with {:ok, magic_key} <- Pleroma.Web.Salmon.fetch_magic_key(body), {:ok, doc} <- Pleroma.Web.Salmon.decode_and_validate(magic_key, body) do {:ok, doc} else _e -> with [decoded | _] <- Pleroma.Web.Salmon.decode(body), doc <- XML.parse_document(decoded), uri when not is_nil(uri) <- XML.string_from_xpath("/entry/author[1]/uri", doc), {:ok, _} <- Pleroma.Web.OStatus.make_user(uri, true), {:ok, magic_key} <- Pleroma.Web.Salmon.fetch_magic_key(body), {:ok, doc} <- Pleroma.Web.Salmon.decode_and_validate(magic_key, body) do {:ok, doc} end end end def salmon_incoming(conn, _) do {:ok, body, _conn} = read_body(conn) {:ok, doc} = decode_or_retry(body) Federator.incoming_doc(doc) send_resp(conn, 200, "") end def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) when format in ["json", "activity+json"] do ActivityPubController.call(conn, :object) end def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :object, uuid), {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do case format do "html" -> redirect(conn, to: "/notice/#{activity.id}") _ -> represent_activity(conn, nil, activity, user) end else reason when reason in [{:public?, false}, {:activity, nil}] -> {:error, :not_found} e -> e end end def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) when format in ["json", "activity+json"] do ActivityPubController.call(conn, :activity) end def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :activity, uuid), {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do case format do "html" -> redirect(conn, to: "/notice/#{activity.id}") _ -> represent_activity(conn, format, activity, user) end else reason when reason in [{:public?, false}, {:activity, nil}] -> {:error, :not_found} e -> e end end def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do cond do format == "html" && activity.data["type"] == "Create" -> %Object{} = object = Object.normalize(activity) RedirectController.redirector_with_meta( conn, %{ activity_id: activity.id, object: object, url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), user: user } ) format == "html" -> RedirectController.redirector(conn, nil) true -> represent_activity(conn, format, activity, user) end else reason when reason in [{:public?, false}, {:activity, nil}] -> conn |> put_status(404) |> RedirectController.redirector(nil, 404) e -> e end end # Returns an HTML embedded