Current section

Files

Jump to
sql_membership_provider lib sql_membership_provider membership.ex
Raw

lib/sql_membership_provider/membership.ex

defmodule SqlMembershipProvider.Membership do
@moduledoc """
Struct for representing a user's membership to an application and their authentication information.
"""
use TypedEctoSchema
import Ecto.Query, only: [from: 2]
@primary_key {:user_id, :binary_id, null: false}
@field_source_mapper fn name -> name |> Atom.to_string() |> Macro.camelize() end
typed_schema "aspnet_Membership" do
field(:password, :string, null: false)
field(:password_format, :integer, null: false)
field(:password_salt, :string, null: false)
field(:mobile_pin, :string)
field(:email, :string)
field(:lowered_email, :string)
field(:password_question, :string)
field(:password_answer, :string)
field(:is_approved, :boolean, null: false)
field(:is_locked_out, :boolean, null: false)
field(:create_date, :utc_datetime, null: false)
field(:last_login_date, :utc_datetime, null: false)
field(:last_password_changed_date, :utc_datetime, null: false)
field(:last_lockout_date, :utc_datetime, null: false)
field(:failed_password_attempt_count, :integer, null: false)
field(:failed_password_attempt_window_start, :utc_datetime, null: false)
field(:failed_password_answer_attempt_count, :integer, null: false)
field(:failed_password_answer_attempt_window_start, :utc_datetime, null: false)
field(:comment, :string)
belongs_to(:application, SqlMembershipProvider.Application,
references: :application_id,
type: :binary_id
)
belongs_to(:user, SqlMembershipProvider.User,
define_field: false,
primary_key: true,
references: :user_id
)
end
@doc """
Fetch a membership by user id.
"""
@spec find_by_user_id(String.t()) :: Ecto.Query.t()
def find_by_user_id(user_id) when is_binary(user_id) do
from(
m in SqlMembershipProvider.Membership,
where: m.user_id == ^user_id
)
end
@doc """
Check if a plaintext password matches a user's hashed password.
"""
@spec is_password_valid?(
SqlMembershipProvider.Membership.t(),
String.t()
) :: boolean()
def is_password_valid?(
%SqlMembershipProvider.Membership{
password: hashed_password,
password_format: format,
password_salt: salt
},
password
)
when is_binary(password) do
hash_password(password, format, salt) == hashed_password
end
defp hash_password(password, 1, salt) do
salt = Base.decode64!(salt)
password =
String.to_charlist(password)
|> :unicode.characters_to_binary(:utf8, {:utf16, :little})
:crypto.hash(:sha, salt <> password)
|> Base.encode64()
end
defp hash_password(_password, format, _salt),
do: raise(SqlMembershipProvider.UnsupportedPasswordFormatError, format)
end