Beamlet.Owner (Beamlet v0.1.1)

Copy Markdown View Source

The beamlet's owner, the one user who signs in to the app.

beamlet setup sets the owner up from the command line. From code, the same steps look like this:

case Beamlet.Owner.find() do
  {:ok, owner} ->
    Beamlet.Owner.update(owner, password: "a new passphrase")

  {:error, :not_found} ->
    Beamlet.Owner.create(email: "ada@example.com", password: "correct horse")
end

There is only ever one owner. A second create/1 fails, and the owner cannot be deleted. A new password signs every browser out.

The session functions back the sign-in form. Most callers will not need them.

Summary

Types

A browser signed in as the owner.

The owner, with their email and the password's hash.

Functions

Turns an email and password into the owner, for the sign-in form.

Turns a browser's session secret into the owner.

Creates the owner from an email and a password.

Creates a session for a web sign-in.

Deletes the session a secret names, signing its browser out.

The owner, or {:error, :not_found} before the first beamlet setup.

Updates the owner's email, password or both.

Types

session()

@type session() :: %Beamlet.Session{
  __meta__: term(),
  id: term(),
  inserted_at: term(),
  secret: term(),
  secret_hash: term(),
  updated_at: term()
}

A browser signed in as the owner.

secret is virtual, set only on the struct create_session/0 returns.

user()

@type user() :: %Beamlet.User{
  __meta__: term(),
  email: term(),
  id: term(),
  inserted_at: term(),
  password: term(),
  password_hash: term(),
  updated_at: term()
}

The owner, with their email and the password's hash.

password is virtual and never loaded.

Functions

authenticate(email, password)

@spec authenticate(term(), term()) :: {:ok, user()} | {:error, :invalid_credentials}

Turns an email and password into the owner, for the sign-in form.

A wrong email, a wrong password and a beamlet with no owner yet all fail the same way, {:error, :invalid_credentials}, and take the same time, so the reply reveals nothing about which. A password longer than the owner can have fails the same way without being hashed, since hashing cost grows with its length.

authenticate_session(secret)

@spec authenticate_session(term()) :: {:ok, user()} | {:error, :unknown_session}

Turns a browser's session secret into the owner.

Anything that is not the secret of a stored session, including one that was signed out, is {:error, :unknown_session}.

create(attrs)

@spec create(map() | keyword()) :: {:ok, user()} | {:error, Ecto.Changeset.t()}

Creates the owner from an email and a password.

A second create fails. Use update/2 to change the owner.

create_session()

@spec create_session() :: {:ok, session()} | {:error, Ecto.Changeset.t()}

Creates a session for a web sign-in.

The returned session carries its secret. Nothing else ever will.

delete_session(secret)

@spec delete_session(term()) :: :ok

Deletes the session a secret names, signing its browser out.

A secret that names no session is a no-op.

find()

@spec find() :: {:ok, user()} | {:error, :not_found}

The owner, or {:error, :not_found} before the first beamlet setup.

update(user, attrs)

@spec update(user(), map() | keyword()) ::
  {:ok, user()} | {:error, Ecto.Changeset.t()}

Updates the owner's email, password or both.

A new password signs every browser out. A new email does not.