Packages
pow
1.0.14
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/extensions/reset_password/plug.ex
defmodule PowResetPassword.Plug do
@moduledoc """
Plug helper methods.
"""
alias Plug.Conn
alias Pow.{Config, Plug, Store.Backend.EtsCache, UUID}
alias PowResetPassword.Ecto.Context, as: ResetPasswordContext
alias PowResetPassword.{Ecto.Schema, Store.ResetTokenCache}
@doc """
Creates a changeset from the user fetched in the connection.
"""
@spec change_user(Conn.t(), map()) :: map()
def change_user(conn, params \\ %{}) do
user = reset_password_user(conn) || user_struct(conn)
Schema.reset_password_changeset(user, params)
end
defp user_struct(conn) do
conn
|> Plug.fetch_config()
|> Config.user!()
|> struct()
end
@doc """
Assigns a `:reset_password_user` key with the user in the connection.
"""
@spec assign_reset_password_user(Conn.t(), map()) :: Conn.t()
def assign_reset_password_user(conn, user) do
Conn.assign(conn, :reset_password_user, user)
end
@doc """
Finds a user for the provided params, creates a token, and stores the user
for the token.
To prevent timing attacks, `Pow.UUID.generate/0` is called whether the user
exists or not.
`:reset_password_token_store` can be passed in the config for the conn. This
value defaults to
`{PowResetPassword.Store.ResetTokenCache, backend: Pow.Store.Backend.EtsCache}`.
The `Pow.Store.Backend.EtsCache` backend store can be changed with the
`:cache_store_backend` option.
"""
@spec create_reset_token(Conn.t(), map()) :: {:ok, map(), Conn.t()} | {:error, map(), Conn.t()}
def create_reset_token(conn, params) do
config = Plug.fetch_config(conn)
token = UUID.generate()
user =
params
|> Map.get("email")
|> ResetPasswordContext.get_by_email(config)
maybe_store_reset_token(conn, user, token, config)
end
defp maybe_store_reset_token(conn, nil, _token, _config) do
changeset = change_user(conn)
{:error, %{changeset | action: :update}, conn}
end
defp maybe_store_reset_token(conn, user, token, config) do
{store, store_config} = store(config)
store.put(store_config, token, user)
{:ok, %{token: token, user: user}, conn}
end
@doc """
Fetches user from the store by the provided token.
See `create_reset_token/2` for more on `:reset_password_token_store` config
option.
"""
@spec user_from_token(Conn.t(), binary()) :: map() | nil
def user_from_token(conn, token) do
{store, store_config} =
conn
|> Plug.fetch_config()
|> store()
store_config
|> store.get(token)
|> case do
:not_found -> nil
user -> user
end
end
@doc """
Updates the password for the user fetched in the connection.
See `create_reset_token/2` for more on `:reset_password_token_store` config
option.
"""
@spec update_user_password(Conn.t(), map()) :: {:ok, map(), Conn.t()} | {:error, map(), Conn.t()}
def update_user_password(conn, params) do
config = Plug.fetch_config(conn)
token = conn.params["id"]
conn
|> reset_password_user()
|> ResetPasswordContext.update_password(params, config)
|> maybe_expire_token(conn, token, config)
end
defp maybe_expire_token({:ok, user}, conn, token, config) do
expire_token(token, config)
{:ok, user, conn}
end
defp maybe_expire_token({:error, changeset}, conn, _token, _config) do
{:error, changeset, conn}
end
defp expire_token(token, config) do
{store, store_config} = store(config)
store.delete(store_config, token)
end
defp reset_password_user(conn) do
conn.assigns[:reset_password_user]
end
defp store(config) do
case Config.get(config, :reset_password_token_store, default_store(config)) do
{store, store_config} -> {store, store_config}
store -> {store, []}
end
end
defp default_store(config) do
backend = Config.get(config, :cache_store_backend, EtsCache)
{ResetTokenCache, [backend: backend]}
end
end