2019-11-15 03:40:35 +01:00
|
|
|
defmodule PowLockout.Phoenix.ControllerCallbacks do
|
|
|
|
@moduledoc """
|
2019-11-15 17:14:23 +01:00
|
|
|
Controller callback logic for account lockout.
|
2019-11-15 03:40:35 +01:00
|
|
|
|
|
|
|
### User is locked out
|
|
|
|
|
|
|
|
Triggers on `Pow.Phoenix.SessionController.create/2`.
|
|
|
|
|
|
|
|
When a user is locked out, the credentials will be treated as if they were
|
|
|
|
invalid and the user will be redirected back to `Pow.Phoenix.Routes.`.
|
|
|
|
|
|
|
|
### User successfully authenticates
|
|
|
|
|
|
|
|
Triggers on `Pow.Phoenix.SessionController.create/2`.
|
|
|
|
|
|
|
|
When a user successfully signs in, the failed attempts counter will be
|
|
|
|
reset to zero.
|
|
|
|
|
|
|
|
### Users unsuccessfully authenticates
|
|
|
|
|
|
|
|
Triggers on `Pow.Phoenix.SessionController.create/2`.
|
|
|
|
|
|
|
|
When a user unsuccessfully signs in, the failed attempts counter will be
|
|
|
|
incremented, and the user may be locked out.
|
|
|
|
|
|
|
|
See `PowLockout.Ecto.Schema` for more.
|
|
|
|
"""
|
|
|
|
use Pow.Extension.Phoenix.ControllerCallbacks.Base
|
|
|
|
|
|
|
|
alias Plug.Conn
|
|
|
|
alias Pow.Plug
|
|
|
|
alias PowLockout.Phoenix.{UnlockController, Mailer}
|
|
|
|
alias PowLockout.Plug, as: PowLockoutPlug
|
|
|
|
|
|
|
|
@doc false
|
|
|
|
@impl true
|
|
|
|
def before_respond(Pow.Phoenix.SessionController, :create, {result, conn}, _config) do
|
|
|
|
PowLockoutPlug.user_for_attempts(conn)
|
|
|
|
|> maybe_fail_attempt(conn, result)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_fail_attempt(nil, conn, result),
|
|
|
|
do: {result, conn}
|
|
|
|
|
|
|
|
defp maybe_fail_attempt(%{locked_at: nil} = user, conn, :ok) do
|
|
|
|
case PowLockoutPlug.succeed_attempt(conn, user) do
|
|
|
|
{:error, _changeset, conn} ->
|
|
|
|
{:halt, conn}
|
|
|
|
|
|
|
|
{:ok, _user, conn} ->
|
|
|
|
{:ok, conn}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_fail_attempt(_locked_user, conn, :ok) do
|
|
|
|
{:error, invalid_credentials(conn)}
|
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_fail_attempt(user, conn, _error) do
|
|
|
|
PowLockoutPlug.fail_attempt(conn, user)
|
|
|
|
|> case do
|
|
|
|
{:error, _changeset, conn} ->
|
|
|
|
{:halt, conn}
|
|
|
|
|
|
|
|
{:ok, %{locked_at: nil}, conn} ->
|
|
|
|
{:error, invalid_credentials(conn)}
|
|
|
|
|
|
|
|
{:ok, user, conn} ->
|
|
|
|
send_unlock_email(user, conn)
|
|
|
|
|
|
|
|
{:error, invalid_credentials(conn)}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp invalid_credentials(conn) do
|
2020-02-06 23:24:17 +01:00
|
|
|
Plug.delete(conn)
|
2019-11-15 03:40:35 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Sends an unlock e-mail to the user.
|
|
|
|
"""
|
|
|
|
@spec send_unlock_email(map(), Conn.t()) :: any()
|
|
|
|
def send_unlock_email(user, conn) do
|
2020-01-11 05:20:19 +01:00
|
|
|
url = unlock_url(conn, user.unlock_token)
|
2019-11-15 03:40:35 +01:00
|
|
|
email = Mailer.email_unlock(conn, user, url)
|
|
|
|
|
|
|
|
Pow.Phoenix.Mailer.deliver(conn, email)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp unlock_url(conn, token) do
|
|
|
|
routes(conn).url_for(conn, UnlockController, :show, [token])
|
|
|
|
end
|
|
|
|
end
|