summaryrefslogtreecommitdiff
path: root/lib/chessh/schema
diff options
context:
space:
mode:
authorSimponic <loganhunt@simponic.xyz>2022-12-19 02:39:40 -0700
committerSimponic <loganhunt@simponic.xyz>2022-12-19 02:39:40 -0700
commitb4743f9efb685545cdd780cc9ba7a50e083dd8cf (patch)
treea538467211886df38c79706769029e23c7aadb61 /lib/chessh/schema
parent9cdfb6eb9cd30c4e06a7d9fef53e519983827d81 (diff)
downloadchessh-b4743f9efb685545cdd780cc9ba7a50e083dd8cf.tar.gz
chessh-b4743f9efb685545cdd780cc9ba7a50e083dd8cf.zip
Get public key authenticator actually running, add password validator via hash
Diffstat (limited to 'lib/chessh/schema')
-rw-r--r--lib/chessh/schema/player.ex81
-rw-r--r--lib/chessh/schema/repo.ex5
2 files changed, 86 insertions, 0 deletions
diff --git a/lib/chessh/schema/player.ex b/lib/chessh/schema/player.ex
new file mode 100644
index 0000000..7d9bb6e
--- /dev/null
+++ b/lib/chessh/schema/player.ex
@@ -0,0 +1,81 @@
+defmodule Chessh.Player do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ @derive {Inspect, except: [:password]}
+ schema "players" do
+ field(:username, :string)
+
+ field(:password, :string, virtual: true)
+ field(:hashed_password, :string)
+
+ timestamps()
+ end
+
+ def registration_changeset(user, attrs, opts \\ []) do
+ user
+ |> cast(attrs, [:username, :password])
+ |> validate_username()
+ |> validate_password(opts)
+ end
+
+ def password_changeset(user, attrs, opts \\ []) do
+ user
+ |> cast(attrs, [:password])
+ |> validate_confirmation(:password, message: "does not match password")
+ |> validate_password(opts)
+ end
+
+ def valid_password?(%Chessh.Player{hashed_password: hashed_password}, password)
+ when is_binary(hashed_password) and byte_size(password) > 0 do
+ Bcrypt.verify_pass(password, hashed_password)
+ end
+
+ def valid_password?(_, _) do
+ Bcrypt.no_user_verify()
+ false
+ end
+
+ def validate_current_password(changeset, password) do
+ if valid_password?(changeset.data, password) do
+ changeset
+ else
+ add_error(changeset, :current_password, "is not valid")
+ end
+ end
+
+ defp validate_username(changeset) do
+ changeset
+ |> validate_required([:username])
+ |> validate_length(:username, min: 2, max: 12)
+ |> validate_format(:username, ~r/^[a-zA-Z0-9_\-]*$/,
+ message: "only letters, numbers, underscores, and hyphens allowed"
+ )
+ |> unique_constraint(:username)
+ |> lowercase(:username)
+ end
+
+ defp validate_password(changeset, opts) do
+ changeset
+ |> validate_required([:password])
+ |> validate_length(:password, min: 8, max: 80)
+ |> maybe_hash_password(opts)
+ end
+
+ defp maybe_hash_password(changeset, opts) do
+ hash_password? = Keyword.get(opts, :hash_password, true)
+ password = get_change(changeset, :password)
+
+ if hash_password? && password && changeset.valid? do
+ changeset
+ |> put_change(:hashed_password, Bcrypt.hash_pwd_salt(password))
+ |> delete_change(:password)
+ else
+ changeset
+ end
+ end
+
+ defp lowercase(changeset, field) do
+ Map.update!(changeset, field, &String.downcase/1)
+ end
+end
diff --git a/lib/chessh/schema/repo.ex b/lib/chessh/schema/repo.ex
new file mode 100644
index 0000000..27d81b9
--- /dev/null
+++ b/lib/chessh/schema/repo.ex
@@ -0,0 +1,5 @@
+defmodule Chessh.Repo do
+ use Ecto.Repo,
+ otp_app: :chessh,
+ adapter: Ecto.Adapters.Postgres
+end