Merge branch 'develop' into refactor/locked_user_field
[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(Pleroma.Web.Plugs.EnsureAuthenticatedPlug,
20 unless_func: &Pleroma.Web.Plugs.FederatingPlug.federating?/1
21 )
22
23 plug(
24 RateLimiter,
25 [name: :ap_routes, params: ["uuid"]] when action in [:object, :activity]
26 )
27
28 plug(
29 Pleroma.Web.Plugs.SetFormatPlug
30 when action in [:object, :activity, :notice]
31 )
32
33 action_fallback(:errors)
34
35 def object(%{assigns: %{format: format}} = conn, _params)
36 when format in ["json", "activity+json"] do
37 ActivityPubController.call(conn, :object)
38 end
39
40 def object(%{assigns: %{format: format}} = conn, _params) do
41 with id <- Endpoint.url() <> conn.request_path,
42 {_, %Activity{} = activity} <-
43 {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
44 {_, true} <- {:public?, Visibility.is_public?(activity)} do
45 case format do
46 _ -> redirect(conn, to: "/notice/#{activity.id}")
47 end
48 else
49 reason when reason in [{:public?, false}, {:activity, nil}] ->
50 {:error, :not_found}
51
52 e ->
53 e
54 end
55 end
56
57 def activity(%{assigns: %{format: format}} = conn, _params)
58 when format in ["json", "activity+json"] do
59 ActivityPubController.call(conn, :activity)
60 end
61
62 def activity(%{assigns: %{format: format}} = conn, _params) do
63 with id <- Endpoint.url() <> conn.request_path,
64 {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
65 {_, true} <- {:public?, Visibility.is_public?(activity)} do
66 case format do
67 _ -> redirect(conn, to: "/notice/#{activity.id}")
68 end
69 else
70 reason when reason in [{:public?, false}, {:activity, nil}] ->
71 {:error, :not_found}
72
73 e ->
74 e
75 end
76 end
77
78 def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
79 with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
80 {_, true} <- {:public?, Visibility.is_public?(activity)},
81 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
82 cond do
83 format in ["json", "activity+json"] ->
84 if activity.local do
85 %{data: %{"id" => redirect_url}} = Object.normalize(activity)
86 redirect(conn, external: redirect_url)
87 else
88 {:error, :not_found}
89 end
90
91 activity.data["type"] == "Create" ->
92 %Object{} = object = Object.normalize(activity)
93
94 RedirectController.redirector_with_meta(
95 conn,
96 %{
97 activity_id: activity.id,
98 object: object,
99 url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
100 user: user
101 }
102 )
103
104 true ->
105 RedirectController.redirector(conn, nil)
106 end
107 else
108 reason when reason in [{:public?, false}, {:activity, nil}] ->
109 conn
110 |> put_status(404)
111 |> RedirectController.redirector(nil, 404)
112
113 e ->
114 e
115 end
116 end
117
118 # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
119 def notice_player(conn, %{"id" => id}) do
120 with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
121 true <- Visibility.is_public?(activity),
122 %Object{} = object <- Object.normalize(activity),
123 %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
124 true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
125 conn
126 |> put_layout(:metadata_player)
127 |> put_resp_header("x-frame-options", "ALLOW")
128 |> put_resp_header(
129 "content-security-policy",
130 "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
131 )
132 |> put_view(PlayerView)
133 |> render("player.html", url)
134 else
135 _error ->
136 conn
137 |> put_status(404)
138 |> RedirectController.redirector(nil, 404)
139 end
140 end
141
142 defp errors(conn, {:error, :not_found}) do
143 render_error(conn, :not_found, "Not found")
144 end
145
146 defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
147
148 defp errors(conn, _) do
149 render_error(conn, :internal_server_error, "Something went wrong")
150 end
151 end