Packages
ash_authentication
3.8.0
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash_authentication/validations.ex
defmodule AshAuthentication.Validations do
@moduledoc """
Common validations shared by several transformers.
"""
import AshAuthentication.{Sender, Utils}
alias Ash.Resource.Attribute
alias Spark.{Dsl, Dsl.Transformer, Error.DslError}
@doc """
Given a map validate that the provided field is one of the values provided.
"""
@spec validate_field_in_values(map, any, [any]) :: :ok | {:error, String.t()}
def validate_field_in_values(map, field, []) when is_map(map) when is_map_key(map, field),
do: {:error, "Expected `#{inspect(field)}` to not be present."}
def validate_field_in_values(map, _field, []) when is_map(map), do: :ok
def validate_field_in_values(map, field, [value])
when is_map(map) and is_map_key(map, field) and :erlang.map_get(field, map) == value,
do: :ok
def validate_field_in_values(map, field, [value]) when is_map(map) and is_map_key(map, field),
do: {:error, "Expected `#{inspect(field)}` to equal `#{inspect(value)}`"}
def validate_field_in_values(map, field, values)
when is_map(map) and is_list(values) and is_map_key(map, field) do
if Map.get(map, field) in values do
:ok
else
values =
values
|> Enum.map(&"`#{inspect(&1)}`")
|> to_sentence(final: "or")
{:error, "Expected `#{inspect(field)}` to be one of #{values}"}
end
end
def validate_field_in_values(map, field, [value]) when is_map(map),
do: {:error, "Expected `#{inspect(field)}` to be present and equal `#{inspect(value)}`"}
def validate_field_in_values(map, field, values) when is_map(map) and is_list(values) do
values =
values
|> Enum.map(&"`#{inspect(&1)}`")
|> to_sentence(final: "or")
{:error, "Expected `#{inspect(field)}` to be present and contain one of #{values}"}
end
@doc """
Given a map, validate that the provided field predicate returns true for the value.
"""
@spec validate_field_with(map, field, (any -> boolean), message) :: :ok | {:error, message}
when field: any, message: any
def validate_field_with(map, field, predicate, message \\ nil) do
okay? =
map
|> Map.get(field)
|> predicate.()
cond do
okay? ->
:ok
message ->
{:error, message}
true ->
{:error, "Field `#{inspect(field)}` in map `#{inspect(map)}` failed validation."}
end
end
@doc """
Find and return a named attribute in the DSL state.
"""
@spec find_attribute(Dsl.t(), atom) ::
{:ok, Attribute.t()} | {:error, Exception.t()}
def find_attribute(dsl_state, attribute_name) do
dsl_state
|> Transformer.get_entities([:attributes])
|> Enum.find(&(&1.name == attribute_name))
|> case do
nil ->
resource = Transformer.get_persisted(dsl_state, :module)
{:error,
DslError.exception(
path: [:attributes, :attribute],
message:
"The resource `#{inspect(resource)}` does not define an attribute named `#{inspect(attribute_name)}`"
)}
attribute ->
{:ok, attribute}
end
end
@doc """
Find and return a persisted option in the DSL state.
"""
@spec persisted_option(Dsl.t(), atom) :: {:ok, any} | {:error, {:unknown_persisted, atom}}
def persisted_option(dsl_state, option) do
case Transformer.get_persisted(dsl_state, option) do
nil -> {:error, {:unknown_persisted, option}}
value -> {:ok, value}
end
end
@doc """
Ensure that token generation is enabled for the resource.
"""
@spec validate_token_generation_enabled(Dsl.t()) :: :ok | {:error, Exception.t()}
def validate_token_generation_enabled(dsl_state) do
if AshAuthentication.Info.authentication_tokens_enabled?(dsl_state),
do: :ok,
else:
{:error,
DslError.exception(
path: [:tokens],
message: "Token generation must be enabled for password resets to work."
)}
end
@doc """
Ensure that the named module implements a specific behaviour.
"""
@spec validate_behaviour(module, module) :: :ok | {:error, Exception.t()}
def validate_behaviour(module, behaviour) do
if Spark.implements_behaviour?(module, behaviour) do
:ok
else
{:error,
DslError.exception(
path: [:password_reset],
message: "`#{inspect(module)}` must implement the `#{inspect(behaviour)}` behaviour."
)}
end
end
@doc """
Validates that `extension` is present on the resource.
"""
@spec validate_extension(Dsl.t(), module) :: :ok | {:error, Exception.t()}
def validate_extension(dsl_state, extension) do
extensions = Transformer.get_persisted(dsl_state, :extensions, [])
if extension in extensions,
do: :ok,
else:
{:error,
DslError.exception(
path: [:extensions],
message:
"The `#{inspect(extension)}` extension must also be present on this resource for password authentication to work."
)}
end
@doc """
Build an attribute if not present.
"""
@spec maybe_build_attribute(Dsl.t(), atom, (Dsl.t() -> {:ok, Attribute.t()})) :: {:ok, Dsl.t()}
def maybe_build_attribute(dsl_state, attribute_name, builder) do
with {:error, _} <- find_attribute(dsl_state, attribute_name),
{:ok, attribute} <- builder.(dsl_state) do
{:ok, Transformer.add_entity(dsl_state, [:attributes], attribute)}
else
{:ok, attribute} when is_struct(attribute, Attribute) -> {:ok, dsl_state}
{:error, reason} -> {:error, reason}
end
end
end