Merge remote-tracking branch 'upstream/develop' into develop
[akkoma] / lib / pleroma / web / endpoint.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.Endpoint do
6 use Phoenix.Endpoint, otp_app: :pleroma
7
8 require Pleroma.Constants
9
10 alias Pleroma.Config
11
12 socket("/socket", Pleroma.Web.UserSocket)
13
14 plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint])
15
16 plug(Pleroma.Web.Plugs.SetLocalePlug)
17 plug(CORSPlug)
18 plug(Pleroma.Web.Plugs.HTTPSecurityPlug)
19 plug(Pleroma.Web.Plugs.UploadedMedia)
20
21 @static_cache_control "public, no-cache"
22
23 # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files
24 # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well
25 # Cache-control headers are duplicated in case we turn off etags in the future
26 plug(
27 Pleroma.Web.Plugs.InstanceStatic,
28 at: "/",
29 from: :pleroma,
30 only: ["emoji", "images"],
31 gzip: true,
32 cache_control_for_etags: "public, max-age=1209600",
33 headers: %{
34 "cache-control" => "public, max-age=1209600"
35 }
36 )
37
38 plug(Pleroma.Web.Plugs.InstanceStatic,
39 at: "/",
40 gzip: true,
41 cache_control_for_etags: @static_cache_control,
42 headers: %{
43 "cache-control" => @static_cache_control
44 }
45 )
46
47 # Careful! No `only` restriction here, as we don't know what frontends contain.
48 plug(Pleroma.Web.Plugs.FrontendStatic,
49 at: "/",
50 frontend_type: :primary,
51 gzip: true,
52 cache_control_for_etags: @static_cache_control,
53 headers: %{
54 "cache-control" => @static_cache_control
55 }
56 )
57
58 plug(Plug.Static.IndexHtml, at: "/pleroma/admin/")
59
60 plug(Pleroma.Web.Plugs.FrontendStatic,
61 at: "/pleroma/admin",
62 frontend_type: :admin,
63 gzip: true,
64 cache_control_for_etags: @static_cache_control,
65 headers: %{
66 "cache-control" => @static_cache_control
67 }
68 )
69
70 plug(Plug.Static.IndexHtml, at: "/pleroma/fedife/")
71
72 plug(Pleroma.Web.Plugs.FrontendStatic,
73 at: "/pleroma/fedife",
74 frontend_type: :fedife,
75 gzip: true,
76 cache_control_for_etags: @static_cache_control,
77 headers: %{
78 "cache-control" => @static_cache_control
79 }
80 )
81
82 # Serve at "/" the static files from "priv/static" directory.
83 #
84 # You should set gzip to true if you are running phoenix.digest
85 # when deploying your static files in production.
86 plug(
87 Plug.Static,
88 at: "/",
89 from: :pleroma,
90 only: Pleroma.Constants.static_only_files(),
91 # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
92 gzip: true,
93 cache_control_for_etags: @static_cache_control,
94 headers: %{
95 "cache-control" => @static_cache_control
96 }
97 )
98
99 plug(Plug.Static,
100 at: "/pleroma/admin/",
101 from: {:pleroma, "priv/static/adminfe/"}
102 )
103
104 # Code reloading can be explicitly enabled under the
105 # :code_reloader configuration of your endpoint.
106 if code_reloading? do
107 plug(Phoenix.CodeReloader)
108 end
109
110 plug(Pleroma.Web.Plugs.TrailingFormatPlug)
111 plug(Plug.RequestId)
112 plug(Plug.Logger, log: :debug)
113
114 plug(Plug.Parsers,
115 parsers: [
116 :urlencoded,
117 {:multipart, length: {Config, :get, [[:instance, :upload_limit]]}},
118 :json
119 ],
120 pass: ["*/*"],
121 json_decoder: Jason,
122 length: Config.get([:instance, :upload_limit]),
123 body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
124 )
125
126 plug(Plug.MethodOverride)
127 plug(Plug.Head)
128
129 secure_cookies = Config.get([__MODULE__, :secure_cookie_flag])
130
131 cookie_name =
132 if secure_cookies,
133 do: "__Host-pleroma_key",
134 else: "pleroma_key"
135
136 extra =
137 Config.get([__MODULE__, :extra_cookie_attrs])
138 |> Enum.join(";")
139
140 # The session will be stored in the cookie and signed,
141 # this means its contents can be read but not tampered with.
142 # Set :encryption_salt if you would also like to encrypt it.
143 plug(
144 Plug.Session,
145 store: :cookie,
146 key: cookie_name,
147 signing_salt: Config.get([__MODULE__, :signing_salt], "CqaoopA2"),
148 http_only: true,
149 secure: secure_cookies,
150 extra: extra
151 )
152
153 plug(Pleroma.Web.Plugs.RemoteIp)
154
155 defmodule Instrumenter do
156 use Prometheus.PhoenixInstrumenter
157 end
158
159 defmodule PipelineInstrumenter do
160 use Prometheus.PlugPipelineInstrumenter
161 end
162
163 defmodule MetricsExporter do
164 use Prometheus.PlugExporter
165 end
166
167 defmodule MetricsExporterCaller do
168 @behaviour Plug
169
170 def init(opts), do: opts
171
172 def call(conn, opts) do
173 prometheus_config = Application.get_env(:prometheus, MetricsExporter, [])
174 ip_whitelist = List.wrap(prometheus_config[:ip_whitelist])
175
176 cond do
177 !prometheus_config[:enabled] ->
178 conn
179
180 ip_whitelist != [] and
181 !Enum.find(ip_whitelist, fn ip ->
182 Pleroma.Helpers.InetHelper.parse_address(ip) == {:ok, conn.remote_ip}
183 end) ->
184 conn
185
186 true ->
187 MetricsExporter.call(conn, opts)
188 end
189 end
190 end
191
192 plug(PipelineInstrumenter)
193
194 plug(MetricsExporterCaller)
195
196 plug(Pleroma.Web.Router)
197
198 @doc """
199 Dynamically loads configuration from the system environment
200 on startup.
201
202 It receives the endpoint configuration from the config files
203 and must return the updated configuration.
204 """
205 def load_from_system_env(config) do
206 port = System.get_env("PORT") || raise "expected the PORT environment variable to be set"
207 {:ok, Keyword.put(config, :http, [:inet6, port: port])}
208 end
209
210 def websocket_url do
211 String.replace_leading(url(), "http", "ws")
212 end
213 end