Current section

Files

Jump to
maat_feather lib maat_feather users user.ex
Raw

lib/maat_feather/users/user.ex

defmodule MaatFeather.Users.User do
use Ecto.Schema
import Ecto.Changeset
alias MaatFeather.Auth.TOTPSecretKey
@primary_key false
@foreign_key_type :string
schema "users" do
field(:email, :string)
field(:password, :string, virtual: true)
field(:password_hash, :string)
field(:address, :string)
field(:role, :string, default: "user")
field(:username, :string)
field(:has_mfa, :boolean, default: false)
field(:secret_key, TOTPSecretKey, autogenerate: true)
field(:private_key, :string, virtual: true)
field(:public_key, :string, virtual: true)
timestamps()
end
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:username, :email, :password, :role, :address, :password_hash, :secret_key])
|> validate_required([:username, :email, :password, :role])
|> validate_inclusion(:role, [:user, :admin])
|> validate_format(:email, ~r/\A[^@\s]+@[^@\s]+\z/, message: "is not a valid email")
|> validate_length(:password, min: 6, message: "must be at least 6 characters")
|> validate_length(:username, min: 3, message: "must be at least 3 characters")
|> unique_constraint(:address, message: "address is already taken")
|> unique_constraint(:email, message: "email is already taken")
|> unique_constraint(:username, message: "username is already taken")
|> unique_constraint(:secret_key, message: "secret key is already taken")
|> put_params()
end
def put_params(%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset) do
private_key = X509.PrivateKey.new_rsa(1024)
public_key = X509.PublicKey.derive(private_key)
private_key =
private_key
|> X509.PrivateKey.to_pem()
|> Base.encode16()
public_key =
public_key
|> X509.PublicKey.to_pem()
|> Base.encode16()
changeset
|> put_change(:private_key, private_key)
|> put_change(:public_key, public_key)
|> put_change(:address, public_key)
|> change(Argon2.add_hash(password))
end
end