Packages
guard
0.9.0
0.19.1
0.19.0
0.18.0
0.17.2
0.17.1
0.17.0
0.16.3
0.16.2
0.16.1
0.16.0
0.15.3
0.15.2
0.15.1
0.15.0
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.0
0.7.1
0.7.0
0.6.1
0.6.0
0.5.0
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
Useful package for dealing with user authentication and signup
Current section
Files
Jump to
Current section
Files
lib/guard/controller/registration.ex
defmodule Guard.Controller.Registration do
require Logger
use Phoenix.Controller
alias Guard.{Repo, User, Authenticator, Device, Mailer, Users}
import Guard.Controller, only: [send_error: 2, send_error: 3]
def call(conn, opts) do
try do
super(conn, opts)
rescue
error -> send_error(conn, error, :internal_server_error)
end
end
defp check_user(conn, user) do
case user do
nil ->
conn
|> put_status(:not_found)
|> json(%{ok: false})
_ ->
conn
|> put_status(:ok)
|> json(%{ok: true})
end
end
def check_account(conn, %{"username" => username}) do
check_user(conn, Users.get_by_username(username))
end
def check_account(conn, %{"email" => email}) do
check_user(conn, Users.get_by_email(email))
end
def check_account(conn, %{"mobile" => mobile}) do
check_user(conn, Users.get_by_mobile(mobile))
end
def list_all_users(conn, _params) do
users = Guard.Repo.all(Guard.User)
conn
|> json(%{data: users})
end
def create(conn, %{"user" => user}) do
case Authenticator.create_and_confirm_user(user) do
{:ok, user, jwt, extra} ->
conn
|> put_status(:created)
|> json(%{user: user, jwt: jwt, extra: extra})
{:error, error, _} ->
send_error(conn, error)
end
end
def send_password_reset(conn, %{"username" => username}) do
send_password_reset(conn, Users.get_by_username(username), username)
end
def send_password_reset(conn, %{"email" => email}) do
send_password_reset(conn, Users.get_by_email(email), email)
end
def send_password_reset(conn, user, name) do
case user do
nil ->
Logger.debug "Failed to send link to unknown user #{name}"
json conn, %{ok: true} #Do not allow people to probe which users are on the system
user ->
case Authenticator.generate_password_reset_claim(user) do
{:ok, token, _} ->
{:ok, pin, user} = Authenticator.generate_pin(user)
Mailer.send_reset_password_link(user, token, pin)
json conn, %{ok: true}
_ ->
Logger.debug "Failed to generate claim for #{name}"
json conn, %{ok: true} #Do not allow people to probe which users are on the system
end
end
end
def send_login_link(conn, %{"username" => username}) do
send_login_link(conn, Users.get_by_username(username), username)
end
def send_login_link(conn, user=%{"email" => email}) do
existing_user = Users.get_by_email(email)
if existing_user do
send_login_link(conn, existing_user, email)
else
create(conn, %{"user" => user})
end
end
def send_login_link(conn, user, name) do
case user do
nil ->
Logger.debug "Failed to send link to unknown user #{name}"
json conn, %{ok: true} #Do not allow people to probe which users are on the system
user ->
case Authenticator.generate_login_claim(user) do
{:ok, token, _} ->
{:ok, pin, user} = Authenticator.generate_pin(user)
Mailer.send_login_link(user, token, pin)
json conn, %{ok: true, user: user}
_ ->
Logger.debug "Failed to generate claim for #{name}"
json conn, %{ok: true} #Do not allow people to probe which users are on the system
end
end
end
defp validate_either_pin(user, pin) do
case User.validate_pin(user, pin) do
:ok -> {:ok, :mobile}
other ->
if user.enc_email_pin do
case User.validate_email_pin(user, pin) do
:ok -> {:ok, :email}
other -> other
end
else
other
end
end
end
defp get_user_from_param(params) do
cond do
username = Map.get(params, "username") -> Users.get_by_username!(username)
email = Map.get(params, "email") -> Users.get_by_email!(email)
mobile = Map.get(params, "mobile") -> Users.get_by_mobile!(mobile)
true -> {:error, :not_found}
end
end
def update_password(conn, %{"pin" => pin, "new_password" => new_password, "new_password_confirmation" => new_password_confirmation} = params) do
user = get_user_from_param(params)
case validate_either_pin(user, pin) do
{:ok, type} ->
case Users.update_user(user, %{"password" => new_password, "password_confirmation" => new_password_confirmation}) do
{:ok, user} ->
if type == :mobile do
Users.confirm_user_mobile(user, Map.get(params, "mobile"))
Authenticator.clear_pin(user)
else
Users.confirm_user_email(user, Map.get(params, "email"))
Authenticator.clear_email_pin(user)
end
json(conn, %{ok: true})
{:error, changeset} ->
send_error(conn, changeset)
end
{:error, error} ->
conn
|> put_status(:unprocessable_entity)
|> send_error(error)
end
end
defp find_device(token, platform) do
Repo.get_by(Device, token: token, platform: platform)
end
def register_device(conn, %{"device" => %{"platform" => platform, "token" => token} = device}) do
user = Authenticator.current_user conn
Logger.debug "Registering '#{token}'"
existing = find_device(token, platform)
model = if existing == nil do
%Device{}
else
existing
end
device = if user != nil do
Map.put(device, "user_id", user.id)
else
device
end
changeset = Device.changeset(model, device)
res = if existing == nil do
Repo.insert(changeset)
else
Repo.update(changeset)
end
case res do
{:ok, updated_device} ->
conn
|> put_status(:created)
|> json(%{device: updated_device})
{:error, changeset} ->
send_error(conn, Repo.changeset_errors(changeset))
end
end
def unregister_device(conn, %{"platform" => platform, "token" => token}) do
user = Authenticator.current_user conn
existing = find_device(token, platform)
if (existing == nil) do
conn
|> put_status(:not_found)
|> json(%{device: nil})
else
if existing.user_id == nil || existing.user_id == user.id do
case Repo.delete(existing) do
{:ok, model} ->
json conn, %{ok: true, device: model}
{:error, changeset} ->
send_error(conn, Repo.changeset_errors(changeset))
end
else
conn
|> put_status(:not_found)
|> json(%{device: nil})
end
end
end
end