ExPassword (expassword v0.2.0) View Source
Documentation for ExPassword.
Link to this section Summary
Functions
Extracts the options and the algorithm used to generate hash.
Hashes password using the given algorithm and options.
Returns true
if the hash has not been issued by algorithm or options are different from the one used to generate hash
Checks if password matches the given hash
This a convenient function which handles ExPassword.verify?/2 and ExPassword.needs_rehash?/3 for you (and takes care of timing attacks)
Link to this section Types
Specs
algorithm() :: module()
Link to this section Functions
Specs
get_options(hash :: ExPassword.Algorithm.hash()) :: {:ok, ExPassword.Algorithm.options()} | {:error, :invalid}
Extracts the options and the algorithm used to generate hash.
Returns {:error, :invalid}
if hash is invalid or not recognized by available_algorithms/0
.
Specs
hash( algorithm :: algorithm(), password :: ExPassword.Algorithm.password(), options :: ExPassword.Algorithm.options() ) :: ExPassword.Algorithm.hash() | no_return()
Hashes password using the given algorithm and options.
algorithm has to be a module present in available_algorithms/0
.
Specs
needs_rehash?( algorithm :: algorithm(), hash :: ExPassword.Algorithm.hash(), options :: ExPassword.Algorithm.options() ) :: boolean() | no_return()
Returns true
if the hash has not been issued by algorithm or options are different from the one used to generate hash
Specs
verify?( password :: ExPassword.Algorithm.password(), hash :: ExPassword.Algorithm.hash() ) :: boolean() | no_return()
Checks if password matches the given hash
Raises a ExPassword.UnidentifiedAlgorithmError
error if any of available_algorithms/0
recognizes hash
verify_and_rehash_if_needed(user, password, field \\ :encrypted_password, algorithm, options, changes \\ [])
View SourceThis a convenient function which handles ExPassword.verify?/2 and ExPassword.needs_rehash?/3 for you (and takes care of timing attacks)
Returns:
{:error, :user_is_nil}
: if user isnil
(not found in your repo, typically after a Repo.get_by/3 operation){:error, :password_missmatch}
: if password does not match the hash in user.field{:ok, []}
: if password is correct (matches the hash in user.field) and does not need to be updated according to algorithm nor options{:ok, a non empty keyword-list}
: if password is correct but needs to be updated, meaning the algorithm and/or options extracted from the hash (user.field) are different from algorithm and/or options to allow you to then update user's hash
A typical usage would be:
# in config/*
config :my_app,
password_algorithm: ExPassword.Bcrypt,
password_options: %{cost: 11}
algorithm = Application.fetch_env!(:my_app, :password_algorithm)
options = Application.fetch_env!(:my_app, :password_options)
user = MyApp.Context.Users.get_user_by(name: login)
case ExPassword.verify_and_rehash_if_needed(user, password, algorithm, options) do
{:ok, changes} ->
if changes != [] do
user
|> Ecto.Changeset.change(changes)
|> MyApp.Repo.update!()
end
# ... (successful authentication) ...
{:error, _reason} ->
# ... (authentication failed) ...
end
The case
above can even be simplified if at each authentication you do additional updates like the following:
case ExPassword.verify_and_rehash_if_needed(user, password, algorithm, options, [last_sign_in: DateTime.utc_now()]) do
{:ok, changes} ->
user
|> Ecto.Changeset.change(changes)
|> MyApp.Repo.update!()
# ... (successful authentication) ...
{:error, _reason} ->
# ... (authentication failed) ...
end