79db112dfda8bea60d03a651cb4ec515886f1b59
[akkoma] / lib / pleroma / web / o_status / o_status_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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_local_create_by_object_ap_id_with_object(id)},
40 {_, true} <- {:public?, Visibility.is_public?(activity)},
41 {_, false} <- {:local_public?, Visibility.is_local_public?(activity)} do
42 redirect(conn, to: "/notice/#{activity.id}")
43 else
44 reason when reason in [{:public?, false}, {:activity, nil}, {:local_public?, true}] ->
45 {:error, :not_found}
46
47 e ->
48 e
49 end
50 end
51
52 def activity(%{assigns: %{format: format}} = conn, _params)
53 when format in ["json", "activity+json"] do
54 ActivityPubController.call(conn, :activity)
55 end
56
57 def activity(conn, _params) do
58 with id <- Endpoint.url() <> conn.request_path,
59 {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
60 {_, true} <- {:public?, Visibility.is_public?(activity)},
61 {_, false} <- {:local_public?, Visibility.is_local_public?(activity)} do
62 redirect(conn, to: "/notice/#{activity.id}")
63 else
64 reason when reason in [{:public?, false}, {:activity, nil}] ->
65 {:error, :not_found}
66
67 e ->
68 e
69 end
70 end
71
72 def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
73 with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
74 {_, true} <- {:public?, Visibility.is_public?(activity)},
75 {_, false} <- {:local_public?, Visibility.is_local_public?(activity)},
76 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
77 cond do
78 format in ["json", "activity+json"] ->
79 %{data: %{"id" => redirect_url}} = Object.normalize(activity, fetch: false)
80 redirect(conn, external: redirect_url)
81
82 activity.data["type"] == "Create" ->
83 %Object{} = object = Object.normalize(activity, fetch: false)
84
85 RedirectController.redirector_with_meta(
86 conn,
87 %{
88 activity_id: activity.id,
89 object: object,
90 url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
91 user: user
92 }
93 )
94
95 true ->
96 RedirectController.redirector(conn, nil)
97 end
98 else
99 reason when reason in [{:public?, false}, {:local_public?, true}, {:activity, nil}] ->
100 conn
101 |> put_status(404)
102 |> RedirectController.redirector(nil, 404)
103
104 e ->
105 e
106 end
107 end
108
109 # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
110 def notice_player(conn, %{"id" => id}) do
111 with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
112 true <- Visibility.is_public?(activity),
113 {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
114 %Object{} = object <- Object.normalize(activity, fetch: false),
115 %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
116 true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
117 conn
118 |> put_layout(:metadata_player)
119 |> put_resp_header("x-frame-options", "ALLOW")
120 |> put_resp_header(
121 "content-security-policy",
122 "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
123 )
124 |> put_view(PlayerView)
125 |> render("player.html", url)
126 else
127 _error ->
128 conn
129 |> put_status(404)
130 |> RedirectController.redirector(nil, 404)
131 end
132 end
133
134 defp errors(conn, {:error, :not_found}) do
135 render_error(conn, :not_found, "Not found")
136 end
137
138 defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
139
140 defp errors(conn, _) do
141 render_error(conn, :internal_server_error, "Something went wrong")
142 end
143 end