Digestif.Hasher behaviour (digestif v0.1.0)

Copy Markdown

Behaviour and migration dispatcher for password hashers.

A hasher is configured as a {module, options} tuple. The module performs one algorithm; this dispatcher identifies the self-describing algorithm in a stored hash and routes verification only to the configured primary or legacy hashers.

Hashers may expose a rehash predicate, configuration validation, aliases for compatible stored prefixes, and a password byte limit. The bundled adapters also perform a small resource preflight before invoking their cryptographic backend.

Use the simpler Digestif facade in ordinary applications. This module is the extension and integration boundary for authentication libraries and custom hashers.

Summary

Functions

Returns whether a verified hash should be replaced by the primary hasher.

Returns a hasher's declared password byte limit, or nil when unlimited.

Validates one hasher tuple and its options.

Validates a primary hasher and its legacy migration set.

Verifies a value against the hasher selected by the stored algorithm.

Types

t()

@type t() :: {module(), keyword()}

Callbacks

algorithm()

(optional)
@callback algorithm() :: String.t()

algorithm_aliases()

(optional)
@callback algorithm_aliases() :: [String.t()]

hash(value, options)

@callback hash(value :: String.t(), options :: keyword()) :: {:ok, String.t()}

needs_rehash?(encoded_hash, options)

(optional)
@callback needs_rehash?(encoded_hash :: String.t(), options :: keyword()) :: boolean()

no_user_verify(value, options)

@callback no_user_verify(value :: String.t(), options :: keyword()) :: false

password_byte_limit()

(optional)
@callback password_byte_limit() :: pos_integer()

validate_options!(options)

(optional)
@callback validate_options!(options :: keyword()) :: :ok

verify(value, encoded_hash, options)

@callback verify(value :: String.t(), encoded_hash :: String.t(), options :: keyword()) ::
  boolean()

Functions

needs_rehash?(encoded_hash, selected_hasher, primary_hasher)

@spec needs_rehash?(String.t(), t(), t()) :: boolean()

Returns whether a verified hash should be replaced by the primary hasher.

A hash verified by a legacy hasher always needs rehashing. For the primary hasher, its optional needs_rehash?/2 callback decides.

password_byte_limit(hasher)

@spec password_byte_limit(t()) :: pos_integer() | nil

Returns a hasher's declared password byte limit, or nil when unlimited.

validate!(arg1)

@spec validate!(t()) :: :ok

Validates one hasher tuple and its options.

validate_set!(primary, legacy_hashers)

@spec validate_set!(t(), [t()]) :: :ok

Validates a primary hasher and its legacy migration set.

Legacy hashers must declare self-describing algorithm identifiers. All identifiers and aliases must be unique, so dispatch cannot depend on list order.

verify_with_hashers(value, encoded_hash, primary, legacy_hashers)

@spec verify_with_hashers(String.t(), String.t(), t(), [t()]) :: {:ok, t()} | :error

Verifies a value against the hasher selected by the stored algorithm.

Only the primary hasher and explicitly listed legacy hashers are eligible. Unknown or malformed algorithm identifiers fall back to the primary hasher, which must fail closed for foreign encodings.