Safe, whitelist-based casting of values to atoms.
SafeAtom returns only atoms that are explicitly present in the :allowed
list.
Binary input is never converted with String.to_atom/1 or
String.to_existing_atom/1. Instead, binary values are compared with the
string representation of atoms already present in :allowed.
This avoids creating new atoms from external input and avoids querying the VM atom table for arbitrary binary values.
Examples
iex> SafeAtom.cast("user", allowed: [:user, :guest])
{:ok, :user}
iex> SafeAtom.cast(:user, allowed: [:user, :guest])
{:ok, :user}
iex> SafeAtom.cast("admin", allowed: [:user, :guest])
{:error, :not_allowed}
iex> SafeAtom.cast(:admin, allowed: [:user, :guest])
{:error, :not_allowed}
iex> SafeAtom.cast("anything", allowed: [])
{:error, :not_allowed}
iex> SafeAtom.cast("user", [])
{:error, :missing_allowed}
iex> SafeAtom.cast("user", allowed: ["user"])
{:error, :invalid_allowed}
iex> SafeAtom.cast(123, allowed: [:user])
{:error, :invalid_value}
iex> SafeAtom.cast(nil, allowed: [:user])
{:error, :not_allowed}
iex> SafeAtom.cast(nil, allowed: [nil])
{:ok, nil}Error reasons
:missing_allowed- the:allowedoption was not provided.:invalid_allowed-:allowedis not a list of atoms.:invalid_value- the input value is not a binary or an atom.:not_allowed- the input value is valid, but does not match any allowed atom.
Telemetry events
SafeAtom emits the following Telemetry events:
[:safe_atom, :cast, :rejected]
Emitted whenever cast/2 returns {:error, reason}.
- measurements:
:system_time-System.system_time/0at the moment of rejection
- metadata:
:reason- one of:missing_allowed,:invalid_allowed,:invalid_value, or:not_allowed:value- the input value passed tocast/2:allowed- the:allowedoption value, ornilwhen the option is missing
Summary
Functions
Casts a binary or atom to one of the explicitly allowed atoms.
Types
Functions
@spec cast( term(), keyword() ) :: {:ok, atom()} | {:error, reason()}
@spec cast(term(), term()) :: {:error, :missing_allowed}
Casts a binary or atom to one of the explicitly allowed atoms.
The :allowed option is required and must be a list of atoms.
For binary input, SafeAtom compares the input with Atom.to_string/1 for
each allowed atom. The returned atom is always taken from the :allowed list.
Returns {:error, :missing_allowed} when called with options that do not
contain :allowed.
Examples
iex> SafeAtom.cast("user", allowed: [:user, :guest])
{:ok, :user}
iex> SafeAtom.cast(:guest, allowed: [:user, :guest])
{:ok, :guest}
iex> SafeAtom.cast("admin", allowed: [:user, :guest])
{:error, :not_allowed}
iex> SafeAtom.cast(:admin, allowed: [:user, :guest])
{:error, :not_allowed}
iex> SafeAtom.cast("user", allowed: [])
{:error, :not_allowed}
iex> SafeAtom.cast("user", [])
{:error, :missing_allowed}
iex> SafeAtom.cast("user", allowed: :user)
{:error, :invalid_allowed}
iex> SafeAtom.cast("user", allowed: [:user, "guest"])
{:error, :invalid_allowed}
iex> SafeAtom.cast(123, allowed: [:user])
{:error, :invalid_value}
iex> SafeAtom.cast(nil, allowed: [nil])
{:ok, nil}