Skip to content

Instantly share code, notes, and snippets.

@rhbvkleef
Created December 30, 2018 13:01
Show Gist options
  • Save rhbvkleef/f44c4b70f9a064b5480ffa613fe73dc5 to your computer and use it in GitHub Desktop.
Save rhbvkleef/f44c4b70f9a064b5480ffa613fe73dc5 to your computer and use it in GitHub Desktop.
A concept for improving the usability of Comeonin. It may be a good idea to make the hashing modules check the requirements for rehashing so that algorithm-specific settings can be checked as well. This is just a concept for what I would like to see added in comeonin.
defmodule Comeonin.Auto do
if Application.get_env(:comeonin, :hash_algo) == Plain do
:elixir_errors.warn __ENV__.line, __ENV__.file,
"You are using the plain hashing algorithm! This results in passwords being plainly visible in the database! DO NOT USE THIS IN PRODUCTION!"
end
defp get_hash_mod hash do
cond do
String.starts_with?(hash, "$plain") -> Comeonin.Plain
String.starts_with?(hash, "$argon2") -> Comeonin.Argon2
String.starts_with?(hash, "$2") -> Comeonin.Bcrypt
String.starts_with?(hash, "$pbkdf2") -> Comeonin.Pbkdf2
end
end
defp algo do
Module.concat(Comeonin, Application.get_env(:comeonin, :hash_algo))
end
def passwd_hash pass, opts \\ [] do
algo().hashpwsalt pass, opts
end
def passwd_verify hash, pass, opts \\ [] do
get_hash_mod(hash).checkpw pass, hash, opts
end
def dummy_passwd_verify opts \\ [] do
get_hash_mod(hash).dummy_checkpw opts
end
def needs_rehash hash do
get_hash_mod(hash) != algo()
end
end
defmodule Comeonin.Plain do
defp get_hash(%{password_hash: hash}, nil), do: {:ok, hash}
defp get_hash(%{encrypted_password: hash}, nil), do: {:ok, hash}
defp get_hash(_, nil), do: nil
defp get_hash(user, hash_key), do: Map.get(user, hash_key) |> get_hash()
defp get_hash(nil), do: nil
defp get_hash(hash), do: {:ok, hash}
def add_hash(password, opts \\ []) do
hash_key = opts[:hash_key] || :password_hash
%{hash_key => hashpwsalt(password, opts), :password => nil}
end
def check_pass(user, password, opts \\ [])
def check_pass(user, password, opts) do
case get_hash(user, opts[:hash_key]) do
{:ok, hash} ->
(checkpw(password, hash) and {:ok, user}) ||
{:error, "invalid password"}
_ ->
{:error, "no password hash found in the user struct"}
end
end
def hashpwsalt password, opts \\ [] do
"$plain$" <> password
end
def checkpw password, hash do
("$plain$" <> password) == hash
end
def dummy_checkpw opts \\ [] do
false
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment