Packages
guard
0.4.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/models/user.ex
defmodule Guard.User do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@derive {Poison.Encoder, only: [:id, :username, :fullname, :email, :requested_email, :attrs, :inserted_at, :updated_at, :mobile, :requested_mobile]}
schema "users" do
field :username, :string
field :fullname, :string
field :locale, :string
field :email, :string
field :mobile, :string
field :requested_mobile, :string
field :password, :string, virtual: true
field :enc_password, :string
field :perms, :map
field :requested_email, :string
field :provider, :map
field :confirmation_token, :string
field :attrs, :map
field :pin, :string, virtual: true
field :enc_pin, :string
field :pin_expiration, :utc_datetime
timestamps()
end
@required_fields ~w(username)a
@optional_fields ~w(password email enc_password perms requested_email provider confirmation_token fullname locale attrs pin enc_pin pin_expiration mobile requested_mobile)a
@doc """
Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned
with no validation performed.
"""
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> validate_format(:email, ~r/@/)
|> validate_format(:requested_email, ~r/@/)
|> validate_length(:password, min: 6)
|> validate_length(:username, min: 1)
|> validate_confirmation(:password, message: "password_mismatch")
|> update_change(:email, &downcase/1) #Lowercase email, so we can check for duplicates
|> update_change(:requested_email, &downcase/1) #Lowercase email, so we can check for duplicates
|> update_change(:username, &downcase/1) #Lowercase username, so we can check for duplicates
|> unique_constraint(:email, message: "email_taken")
|> unique_constraint(:mobile, message: "mobile_taken")
|> unique_constraint(:username, message: "username_taken")
|> encrypt_password()
|> encrypt_pin()
end
defp downcase(v) do
if v != nil do
v |> String.trim() |> String.downcase()
else
v
end
end
def hash_password(password) do
Comeonin.Bcrypt.hashpwsalt(password)
end
def check_password(user, password) do
Comeonin.Bcrypt.checkpw(password, user.enc_password)
end
def check_pin(user, pin) do
user.enc_pin != nil
&& user.pin_expiration != nil
&& DateTime.diff(DateTime.utc_now(), user.pin_expiration) < 0
&& Comeonin.Bcrypt.checkpw(pin, user.enc_pin)
end
defp encrypt_password(current_changeset) do
case current_changeset do
%Ecto.Changeset{valid?: true, changes: %{password: password}} ->
put_change(current_changeset, :enc_password, hash_password(password))
_ ->
current_changeset
end
end
defp encrypt_pin(current_changeset) do
case current_changeset do
%Ecto.Changeset{valid?: true, changes: %{pin: pin}} ->
put_change(current_changeset, :enc_pin, hash_password(pin))
_ ->
current_changeset
end
end
end