defmodule Dialup.Auth.Hash do @moduledoc """ Password hashing wrapper. Uses `:bcrypt_elixir` when available; otherwise falls back to a deterministic test hasher so Dialup tests compile without optional deps. """ @doc false def hash_password(password) when is_binary(password) do if bcrypt_loaded?() do apply(Bcrypt, :hash_pwd_salt, [password]) else if test_env?() do "test:" <> Base.encode64(:crypto.hash(:sha256, password)) else raise ArgumentError, "bcrypt_elixir is required to hash passwords outside the :test environment" end end end @doc false def valid_password?(password, hash) when is_binary(password) and is_binary(hash) do cond do bcrypt_loaded?() -> apply(Bcrypt, :verify_pass, [password, hash]) String.starts_with?(hash, "test:") -> hash == "test:" <> Base.encode64(:crypto.hash(:sha256, password)) true -> false end end defp bcrypt_loaded? do case :code.ensure_loaded(Bcrypt) do {:module, Bcrypt} -> true _ -> false end end defp test_env? do Code.ensure_loaded?(Mix) and function_exported?(Mix, :env, 0) and Mix.env() == :test end end