summaryrefslogtreecommitdiff
path: root/lib/pleroma/web/web.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web/web.ex')
-rw-r--r--lib/pleroma/web/web.ex105
1 files changed, 86 insertions, 19 deletions
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index bf48ce26c..4f9281851 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -2,6 +2,11 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
+defmodule Pleroma.Web.Plug do
+ # Substitute for `call/2` which is defined with `use Pleroma.Web, :plug`
+ @callback perform(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
+end
+
defmodule Pleroma.Web do
@moduledoc """
A module that keeps using definitions for controllers,
@@ -20,44 +25,91 @@ defmodule Pleroma.Web do
below.
"""
+ alias Pleroma.Plugs.EnsureAuthenticatedPlug
+ alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
+ alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug
+ alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug
+ alias Pleroma.Plugs.OAuthScopesPlug
+ alias Pleroma.Plugs.PlugHelper
+
def controller do
quote do
use Phoenix.Controller, namespace: Pleroma.Web
import Plug.Conn
+
import Pleroma.Web.Gettext
import Pleroma.Web.Router.Helpers
import Pleroma.Web.TranslationHelpers
- alias Pleroma.Plugs.PlugHelper
-
plug(:set_put_layout)
defp set_put_layout(conn, _) do
put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
end
- # Marks a plug intentionally skipped and blocks its execution if it's present in plugs chain
- defp skip_plug(conn, plug_module) do
- try do
- plug_module.skip_plug(conn)
- rescue
- UndefinedFunctionError ->
- raise "#{plug_module} is not skippable. Append `use Pleroma.Web, :plug` to its code."
- end
+ # Marks plugs intentionally skipped and blocks their execution if present in plugs chain
+ defp skip_plug(conn, plug_modules) do
+ plug_modules
+ |> List.wrap()
+ |> Enum.reduce(
+ conn,
+ fn plug_module, conn ->
+ try do
+ plug_module.skip_plug(conn)
+ rescue
+ UndefinedFunctionError ->
+ raise "`#{plug_module}` is not skippable. Append `use Pleroma.Web, :plug` to its code."
+ end
+ end
+ )
end
# Executed just before actual controller action, invokes before-action hooks (callbacks)
defp action(conn, params) do
- with %Plug.Conn{halted: false} <- maybe_halt_on_missing_oauth_scopes_check(conn) do
+ with %{halted: false} = conn <- maybe_drop_authentication_if_oauth_check_ignored(conn),
+ %{halted: false} = conn <- maybe_perform_public_or_authenticated_check(conn),
+ %{halted: false} = conn <- maybe_perform_authenticated_check(conn),
+ %{halted: false} = conn <- maybe_halt_on_missing_oauth_scopes_check(conn) do
super(conn, params)
end
end
+ # For non-authenticated API actions, drops auth info if OAuth scopes check was ignored
+ # (neither performed nor explicitly skipped)
+ defp maybe_drop_authentication_if_oauth_check_ignored(conn) do
+ if PlugHelper.plug_called?(conn, ExpectPublicOrAuthenticatedCheckPlug) and
+ not PlugHelper.plug_called_or_skipped?(conn, OAuthScopesPlug) do
+ OAuthScopesPlug.drop_auth_info(conn)
+ else
+ conn
+ end
+ end
+
+ # Ensures instance is public -or- user is authenticated if such check was scheduled
+ defp maybe_perform_public_or_authenticated_check(conn) do
+ if PlugHelper.plug_called?(conn, ExpectPublicOrAuthenticatedCheckPlug) do
+ EnsurePublicOrAuthenticatedPlug.call(conn, %{})
+ else
+ conn
+ end
+ end
+
+ # Ensures user is authenticated if such check was scheduled
+ # Note: runs prior to action even if it was already executed earlier in plug chain
+ # (since OAuthScopesPlug has option of proceeding unauthenticated)
+ defp maybe_perform_authenticated_check(conn) do
+ if PlugHelper.plug_called?(conn, ExpectAuthenticatedCheckPlug) do
+ EnsureAuthenticatedPlug.call(conn, %{})
+ else
+ conn
+ end
+ end
+
# Halts if authenticated API action neither performs nor explicitly skips OAuth scopes check
defp maybe_halt_on_missing_oauth_scopes_check(conn) do
- if Pleroma.Plugs.AuthExpectedPlug.auth_expected?(conn) &&
- not PlugHelper.plug_called_or_skipped?(conn, Pleroma.Plugs.OAuthScopesPlug) do
+ if PlugHelper.plug_called?(conn, ExpectAuthenticatedCheckPlug) and
+ not PlugHelper.plug_called_or_skipped?(conn, OAuthScopesPlug) do
conn
|> render_error(
:forbidden,
@@ -132,7 +184,8 @@ defmodule Pleroma.Web do
def plug do
quote do
- alias Pleroma.Plugs.PlugHelper
+ @behaviour Pleroma.Web.Plug
+ @behaviour Plug
@doc """
Marks a plug intentionally skipped and blocks its execution if it's present in plugs chain.
@@ -146,14 +199,28 @@ defmodule Pleroma.Web do
end
@impl Plug
- @doc "If marked as skipped, returns `conn`, and calls `perform/2` otherwise."
+ @doc """
+ Before-plug hook that
+ * ensures the plug is not skipped
+ * processes `:if_func` / `:unless_func` functional pre-run conditions
+ * adds plug to the list of called plugs and calls `perform/2` if checks are passed
+
+ Note: multiple invocations of the same plug (with different or same options) are allowed.
+ """
def call(%Plug.Conn{} = conn, options) do
- if PlugHelper.plug_skipped?(conn, __MODULE__) do
+ if PlugHelper.plug_skipped?(conn, __MODULE__) ||
+ (options[:if_func] && !options[:if_func].(conn)) ||
+ (options[:unless_func] && options[:unless_func].(conn)) do
conn
else
- conn
- |> PlugHelper.append_to_private_list(PlugHelper.called_plugs_list_id(), __MODULE__)
- |> perform(options)
+ conn =
+ PlugHelper.append_to_private_list(
+ conn,
+ PlugHelper.called_plugs_list_id(),
+ __MODULE__
+ )
+
+ apply(__MODULE__, :perform, [conn, options])
end
end
end