Packages
openmaize
0.15.1
3.0.1
retired
3.0.0
2.9.0
2.8.0
2.7.0
2.6.0
2.5.1
2.5.0
2.4.0
2.3.2
2.3.1
2.3.0
2.2.0
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.2
2.0.1
2.0.0
1.0.1
1.0.0
1.0.0-beta.5
1.0.0-beta.4
1.0.0-beta.3
1.0.0-beta.2
1.0.0-beta.1
1.0.0-beta.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.8.1
0.8.0
0.7.5
0.7.4
0.7.2
0.7.1
0.7.0
0.6.7
0.6.6
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.1
0.4.0
Authentication library for Elixir using Plug
Current section
Files
Jump to
Current section
Files
lib/openmaize/plugs/confirm.ex
defmodule Openmaize.Confirm do
@moduledoc """
Module to help with email confirmation.
This module can be used for account confirmation by email or for
resetting a password.
See the documentation for `add_confirm_token` and `add_reset_token` in
the Openmaize.Signup module for details about creating the token.
"""
use Openmaize.Pipe
import Comeonin.Tools
import Ecto.Changeset
import Openmaize.Report
alias Openmaize.{Config, QueryTools, Signup}
@doc """
Function to confirm a user's email address.
## Options
There are five options:
* key_expires_after - the length, in minutes, that the token is valid for
* the default is 1440 minutes, or one day
* unique_id - the identifier in the query string, or the parameters
* the default is :email
* mail_function - the emailing function that you need to define
* redirects - if Openmaize should handle the redirects or not
* the default true
* query_function - the function to query the database
* if you are using Ecto, you will probably not need this
## Examples
First, define a `get "/confirm"` route in the web/router.ex file.
Then, in the controller file, `import Openmaize.Confirm` and run the
following command:
plug :confirm_email, [mail_function: &Mailer.send_receipt/1] when action in [:confirm]
This command will be run when the user accesses the `confirm` route.
There is no need to write a confirm function in your controller.
"""
def confirm_email(%Plug.Conn{params: %{"key" => key} = user_params} = conn, opts)
when byte_size(key) == 32 do
check_user_key(conn, user_params, key, :nopassword, get_opts(opts))
end
def confirm_email(conn, opts), do: invalid_link_error(conn, opts)
@doc """
Function to authenticate a user when resetting the password.
See the documentation for `confirm_email` for details about the available
options.
## Reset password form
This function is to be used with the `reset` post request. For the
`reset` get request, you need to render a form with the name "user",
using `[as: :user]` if you are using Phoenix's `form_for` function,
which contains values for the password, email and key (the email and
key should be hidden inputs).
Any password validation needs to be done on the front-end.
## Examples
First, define a `post "/reset", SomeController, :reset_password` route
in the web/router.ex file. Then, in the controller file, `import Openmaize.Confirm`
and run the following command:
plug :reset_password, [mail_function: &Mailer.send_receipt/1] when action in [:reset_password]
This command will be run when the user sends the form with the data to
reset the password. There is no need to write a reset_password function
in your controller, but you will need to write a function to handle the
`get "/reset"` request, that is, to render the form to reset the password.
"""
def reset_password(%Plug.Conn{params: %{"user" =>
%{"key" => key, "password" => password} = user_params}} = conn, opts)
when byte_size(key) == 32 do
check_user_key(conn, user_params, key, password, get_opts(opts))
end
def reset_password(conn, opts), do: invalid_link_error(conn, opts)
defp get_opts(opts) do
{Keyword.get(opts, :key_expires_after, 1440),
Keyword.get(opts, :unique_id, :email),
Keyword.get(opts, :mail_function),
Keyword.get(opts, :redirects, true),
Keyword.get(opts, :query_function, &QueryTools.find_user/2)}
end
defp check_user_key(conn, user_params, key, password,
{key_expiry, uniq, mail_func, redirects, query_func}) do
user_id = Map.get(user_params, to_string(uniq))
error_pipe(user_id
|> URI.decode_www_form
|> query_func.(uniq)
|> check_key(key, key_expiry * 60, password))
|> finalize(conn, user_id, mail_func, redirects)
end
defp check_key(nil, _, _, _), do: false
defp check_key(user, key, valid_secs, :nopassword) do
check_time(user.confirmation_sent_at, valid_secs) and
secure_check(user.confirmation_token, key) and
change(user, %{confirmed_at: Ecto.DateTime.utc}) |> Config.repo.update
end
defp check_key(user, key, valid_secs, password) do
check_time(user.reset_sent_at, valid_secs) and
secure_check(user.reset_token, key) and
Signup.reset_password(user, password)
end
defp check_time(nil, _), do: false
defp check_time(sent_at, valid_secs) do
(sent_at |> Ecto.DateTime.to_erl
|> :calendar.datetime_to_gregorian_seconds) + valid_secs >
(:calendar.universal_time |> :calendar.datetime_to_gregorian_seconds)
end
defp finalize({:ok, user}, conn, _, mail_func, redirects) do
mail_func && mail_func.(user.email)
put_message(conn, %{"info" => "Account successfully confirmed"}, redirects)
end
defp finalize(_, conn, user_id, _, redirects) do
put_message(conn, "logout", %{"error" => "Confirmation for #{user_id} failed"}, redirects)
end
defp invalid_link_error(conn, opts) do
redirects = Keyword.get(opts, :redirects, true)
put_message(conn, "logout", %{"error" => "Invalid link"}, redirects)
end
end