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