defmodule Rivet.Ident.Factor do
@moduledoc """
Schema for representing and working with an AuthFactor.
"""
use TypedEctoSchema
alias Rivet.Ident
use Rivet.Ecto.Model, export_json: [:name, :expires_at, :value, :details]
import EctoEnum
defenum(Types,
unknown: 0,
password: 1,
federated: 2,
valtok: 3,
apikey: 4,
proxy: 5,
access: 6
)
defenum(FederatedTypes,
none: 0,
google: 1,
linkedin: 2,
facebook: 3,
twitter: 4,
twitch: 5
)
typed_schema "ident_factors" do
# identity vs authentication
field(:type, Types)
field(:fedtype, FederatedTypes, default: :none)
field(:name, :string)
field(:expires_at, :integer)
field(:value, :string)
field(:details, Rivet.Utils.Ecto.AtomKeymap)
# we put these back as passwords
field(:password, :string, virtual: true)
# we don't store these again
field(:secret, :string, virtual: true)
field(:hash, :string)
timestamps()
belongs_to(:user, Ident.User, type: :binary_id, foreign_key: :user_id)
end
@required_fields [:type, :expires_at, :user_id]
@update_fields [:fedtype, :name, :value, :details, :password]
use Rivet.Ecto.Collection, required: @required_fields, update: @update_fields
@behaviour Rivet.Ecto.Collection
@impl Rivet.Ecto.Collection
def build(params) do
%__MODULE__{}
|> cast(params, @required_fields ++ @update_fields)
|> validate()
|> hash_password()
end
def hash_password(changeset = %Ecto.Changeset{valid?: true, changes: %{password: pass}}) do
put_change(changeset, :hash, Ident.Factor.Password.hash(pass))
# consider: delete password: token?
end
def hash_password(changeset), do: changeset
end