Merge remote-tracking branch 'remotes/origin/develop' into ostatus-controller-no...
[akkoma] / lib / pleroma / web / o_status / o_status_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.OStatus.OStatusController do
6 use Pleroma.Web, :controller
7
8 alias Pleroma.Activity
9 alias Pleroma.Object
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPubController
12 alias Pleroma.Web.ActivityPub.Visibility
13 alias Pleroma.Web.Endpoint
14 alias Pleroma.Web.Fallback.RedirectController
15 alias Pleroma.Web.Metadata.PlayerView
16 alias Pleroma.Web.Plugs.RateLimiter
17 alias Pleroma.Web.Router
18
19 plug(
20 RateLimiter,
21 [name: :ap_routes, params: ["uuid"]] when action in [:object, :activity]
22 )
23
24 plug(
25 Pleroma.Web.Plugs.SetFormatPlug
26 when action in [:object, :activity, :notice]
27 )
28
29 action_fallback(:errors)
30
31 def object(%{assigns: %{format: format}} = conn, _params)
32 when format in ["json", "activity+json"] do
33 ActivityPubController.call(conn, :object)
34 end
35
36 def object(conn, _params) do
37 with id <- Endpoint.url() <> conn.request_path,
38 {_, %Activity{} = activity} <-
39 {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
40 {_, true} <- {:public?, Visibility.is_public?(activity)} do
41 redirect(conn, to: "/notice/#{activity.id}")
42 else
43 reason when reason in [{:public?, false}, {:activity, nil}] ->
44 {:error, :not_found}
45
46 e ->
47 e
48 end
49 end
50
51 def activity(%{assigns: %{format: format}} = conn, _params)
52 when format in ["json", "activity+json"] do
53 ActivityPubController.call(conn, :activity)
54 end
55
56 def activity(conn, _params) do
57 with id <- Endpoint.url() <> conn.request_path,
58 {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
59 {_, true} <- {:public?, Visibility.is_public?(activity)} do
60 redirect(conn, to: "/notice/#{activity.id}")
61 else
62 reason when reason in [{:public?, false}, {:activity, nil}] ->
63 {:error, :not_found}
64
65 e ->
66 e
67 end
68 end
69
70 def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
71 with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
72 {_, true} <- {:public?, Visibility.is_public?(activity)},
73 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
74 cond do
75 format in ["json", "activity+json"] ->
76 if activity.local do
77 %{data: %{"id" => redirect_url}} = Object.normalize(activity)
78 redirect(conn, external: redirect_url)
79 else
80 {:error, :not_found}
81 end
82
83 activity.data["type"] == "Create" ->
84 %Object{} = object = Object.normalize(activity)
85
86 RedirectController.redirector_with_meta(
87 conn,
88 %{
89 activity_id: activity.id,
90 object: object,
91 url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
92 user: user
93 }
94 )
95
96 true ->
97 RedirectController.redirector(conn, nil)
98 end
99 else
100 reason when reason in [{:public?, false}, {:activity, nil}] ->
101 conn
102 |> put_status(404)
103 |> RedirectController.redirector(nil, 404)
104
105 e ->
106 e
107 end
108 end
109
110 # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
111 def notice_player(conn, %{"id" => id}) do
112 with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
113 true <- Visibility.is_public?(activity),
114 {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
115 %Object{} = object <- Object.normalize(activity),
116 %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
117 true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
118 conn
119 |> put_layout(:metadata_player)
120 |> put_resp_header("x-frame-options", "ALLOW")
121 |> put_resp_header(
122 "content-security-policy",
123 "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
124 )
125 |> put_view(PlayerView)
126 |> render("player.html", url)
127 else
128 _error ->
129 conn
130 |> put_status(404)
131 |> RedirectController.redirector(nil, 404)
132 end
133 end
134
135 defp errors(conn, {:error, :not_found}) do
136 render_error(conn, :not_found, "Not found")
137 end
138
139 defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
140
141 defp errors(conn, _) do
142 render_error(conn, :internal_server_error, "Something went wrong")
143 end
144 end