Current section
Files
Jump to
Current section
Files
lib/shield/policies/login.ex
defmodule Shield.Policy.Login do
alias Authable.Utils.Crypt, as: CryptUtil
alias Shield.Arm.OneTimePassword, as: OneTimePasswordArm
@repo Application.get_env(:authable, :repo)
@user Application.get_env(:authable, :resource_owner)
def check(params) do
params
|> validate_email_exists()
|> validate_email_password_match()
|> validate_email_confirmation()
|> validate_one_time_password()
end
defp validate_email_exists(%{"email" => email} = params) do
case @repo.get_by(@user, email: email) do
nil -> {:error, {:unauthorized, %{email: ["Email could not found."]}}}
user -> {:ok, Map.put(params, "user", user)}
end
end
defp validate_email_password_match({:ok, %{"user" => user, "password" => password} = params}) do
case CryptUtil.match_password(password, Map.get(user, :password, "")) do
false -> {:error, {:unauthorized, %{password: ["Wrong password!"]}}}
true -> {:ok, params}
end
end
defp validate_email_password_match({:error, {_status, _errors} = opts}),
do: {:error, opts}
defp validate_email_confirmation({:ok, %{"user" => user} = params}) do
is_email_confirmation_required = Application.get_env(:shield, :confirmable)
is_email_confirmed = Map.get(user.settings || %{}, "confirmed", false)
case {is_email_confirmation_required, is_email_confirmed} do
{false, _} -> {:ok, params}
{true, true} -> {:ok, params}
{_, _} -> {:error, {:unauthorized,
%{email: ["Email confirmation required."]}}}
end
end
defp validate_email_confirmation({:error, {_status, _errors} = opts}),
do: {:error, opts}
defp validate_one_time_password({:ok, %{"user" => user} = params}) do
is_otp_check_required = Application.get_env(:shield, :otp_check)
is_otp_check_enabled = Map.get(user.settings || %{}, "otp_enabled", false)
case {is_otp_check_required, is_otp_check_enabled} do
{nil, _} -> {:ok, params}
{false, _} -> {:ok, params}
{true, false} -> {:ok, params}
{true, true} -> validate_one_time_password_value({:ok, params})
end
end
defp validate_one_time_password({:error, {_status, _errors} = opts}),
do: {:error, opts}
defp validate_one_time_password_value({:ok, %{"user" => user} = params}) do
case OneTimePasswordArm.find_otp_secret_token(user) do
nil ->
{:error, {:unauthorized, %{otp_secret_token: ["Not found"]}}}
token ->
otp_value = Map.get(params, "otp_value", "")
case OneTimePasswordArm.is_valid?(token.value, otp_value) do
false -> {:error, {:unauthorized,
%{otp_value: ["Invalid one time password"]}}}
true -> {:ok, params}
end
end
end
end