Packages
pow
1.0.33
1.0.39
1.0.38
1.0.37
1.0.36
1.0.35
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.1.0-rc.1
0.1.0-alpha.8
0.1.0-alpha.7
retired
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha
Robust user authentication solution
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/pow/phoenix/controllers/controller.ex
defmodule Pow.Phoenix.Controller do
@moduledoc """
Used with Pow Phoenix controllers to handle messages, routes and callbacks.
## Usage
defmodule MyPowExtension.Phoenix.MyController do
use Pow.Phoenix.Controller
def process_new(conn, _params) do
{:ok, :response, conn}
end
def respond_new({:ok, :response, conn}) do
render(conn, "new.html")
end
end
## Configuration options
* `:messages_backend` - See `Pow.Phoenix.Messages` for more.
* `:routes_backend` - See `Pow.Phoenix.Routes` for more.
* `:controller_callbacks` - See
`Pow.Extension.Phoenix.ControllerCallbacks` for more.
"""
alias Plug.Conn
alias Pow.Config
alias Pow.Phoenix.{Messages, PlugErrorHandler, Routes, ViewHelpers}
alias Pow.Plug
@doc false
defmacro __using__(config) do
quote do
use Phoenix.Controller, (
# Credo will complain about unless statement but we want this first
# credo:disable-for-next-line
unless Pow.dependency_vsn_match?(:phoenix, "< 1.7.0") do
[
layouts: [html: Pow.Phoenix.Layouts],
formats: [:html]
]
else
# TODO: Remove when Phoenix 1.7 is required
[namespace: Pow.Phoenix]
end)
import unquote(__MODULE__), only: [require_authenticated: 2, require_not_authenticated: 2, put_no_cache_header: 2]
plug :pow_layout, unquote(config)
def action(conn, _opts), do: unquote(__MODULE__).action(__MODULE__, conn, conn.params)
defp pow_layout(conn, _config), do: ViewHelpers.layout(conn)
unquote(__MODULE__).__define_helper_functions__()
end
end
@doc false
defmacro __define_helper_functions__ do
quote do
def messages(conn), do: unquote(__MODULE__).messages(conn, Messages)
def routes(conn), do: unquote(__MODULE__).routes(conn, Routes)
defoverridable messages: 1, routes: 1
end
end
@doc """
Handles the controller action call.
If a `:controller_callbacks` module has been set in the configuration,
then `before_process` and `before_respond` will be called on this module
on all actions.
"""
@spec action(atom(), Conn.t(), map()) :: Conn.t()
def action(controller, %{private: private} = conn, params) do
action = private.phoenix_action
config = Plug.fetch_config(conn)
callbacks = Config.get(config, :controller_callbacks)
conn
|> maybe_callback(callbacks, :before_process, controller, action, config)
|> process_action(controller, action, params)
|> maybe_callback(callbacks, :before_respond, controller, action, config)
|> respond_action(controller, action)
end
defp process_action({:halt, conn}, _controller, _action, _params), do: {:halt, conn}
defp process_action(conn, controller, action, params) do
apply(controller, String.to_atom("process_#{action}"), [conn, params])
end
defp respond_action({:halt, conn}, _controller, _action), do: conn
defp respond_action(results, controller, action) do
apply(controller, String.to_atom("respond_#{action}"), [results])
end
defp maybe_callback({:halt, conn}, _callbacks, _hook, _controller, _action, _config),
do: {:halt, conn}
defp maybe_callback(results, nil, _hook, _controller, _action, _config), do: results
defp maybe_callback(results, callbacks, hook, controller, action, config) do
apply(callbacks, hook, [controller, action, results, config])
end
@doc """
Fetches messages backend from configuration, or use fallback.
"""
@spec messages(Conn.t(), atom()) :: atom()
def messages(conn, fallback) do
conn
|> Plug.fetch_config()
|> Config.get(:messages_backend, fallback)
end
@doc """
Fetches routes backend from configuration, or use fallback.
"""
@spec routes(Conn.t(), atom()) :: atom()
def routes(conn, fallback) do
conn
|> Plug.fetch_config()
|> Config.get(:routes_backend, fallback)
end
@doc """
Ensures that user has been authenticated.
`Pow.Phoenix.PlugErrorHandler` is used as error handler. See
`Pow.Plug.RequireAuthenticated` for more.
"""
@spec require_authenticated(Conn.t(), Keyword.t()) :: Conn.t()
def require_authenticated(conn, _opts) do
opts = Plug.RequireAuthenticated.init(error_handler: PlugErrorHandler)
Plug.RequireAuthenticated.call(conn, opts)
end
@doc """
Ensures that user hasn't been authenticated.
`Pow.Phoenix.PlugErrorHandler` is used as error handler. See
`Pow.Plug.RequireNotAuthenticated` for more.
"""
@spec require_not_authenticated(Conn.t(), Keyword.t()) :: Conn.t()
def require_not_authenticated(conn, _opts) do
opts = Plug.RequireNotAuthenticated.init(error_handler: PlugErrorHandler)
Plug.RequireNotAuthenticated.call(conn, opts)
end
@default_cache_control_header Conn.get_resp_header(struct(Conn), "cache-control")
@no_cache_control_header "no-cache, no-store, must-revalidate"
@doc """
Ensures that the page can't be cached in browser.
This will add a "cache-control" header with
"no-cache, no-store, must-revalidate" if the cache control header hasn't
been changed from the default value in the `Plug.Conn` struct.
"""
@spec put_no_cache_header(Conn.t(), Keyword.t()) :: Conn.t()
def put_no_cache_header(conn, _opts) do
conn
|> Conn.get_resp_header("cache-control")
|> case do
@default_cache_control_header -> Conn.put_resp_header(conn, "cache-control", @no_cache_control_header)
_any -> conn
end
end
# TODO: Remove when Phoenix 1.7 is required
@spec route_helper(atom()) :: binary()
def route_helper(plug) do
as = Phoenix.Naming.resource_name(plug, "Controller")
[base | _rest] = Module.split(plug)
base = Macro.underscore(base)
"#{base}_#{as}"
end
end