Packages
ash_authentication
5.0.0-rc.2
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/strategies/totp/helpers.ex
# SPDX-FileCopyrightText: 2025 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.Totp.Helpers do
@moduledoc false
@doc """
Converts a DateTime, nil, or unix timestamp to unix timestamp.
Used to normalise `last_totp_at` values for NimbleTOTP's `since` option.
"""
@spec datetime_to_unix(DateTime.t() | nil | integer) :: integer
def datetime_to_unix(nil), do: 0
def datetime_to_unix(%DateTime{} = dt), do: DateTime.to_unix(dt)
def datetime_to_unix(unix) when is_integer(unix), do: unix
@doc """
Converts time values (with optional units) to seconds.
Note: The TOTP transformer already converts time values from DSL config to
seconds, so integers are already in seconds when they reach action code.
Accepts:
- Integer (already in seconds from transformer)
- `{value, :seconds}` - value in seconds
- `{value, :minutes}` - value in minutes
- `{value, :hours}` - value in hours
- `{value, :days}` - value in days
"""
@spec time_to_seconds(integer | {pos_integer, :seconds | :minutes | :hours | :days}) ::
pos_integer
def time_to_seconds(seconds) when is_integer(seconds), do: seconds
def time_to_seconds({value, :days}), do: value * 86_400
def time_to_seconds({value, :hours}), do: value * 3600
def time_to_seconds({value, :minutes}), do: value * 60
def time_to_seconds({value, :seconds}), do: value
@doc """
Validates that a TOTP code is exactly 6 digits.
Returns `:ok` if valid, `{:error, :invalid_format}` otherwise.
"""
@spec validate_totp_code(any) :: :ok | {:error, :invalid_format}
def validate_totp_code(code) when is_binary(code) do
if Regex.match?(~r/^\d{6}$/, code), do: :ok, else: {:error, :invalid_format}
end
def validate_totp_code(_), do: {:error, :invalid_format}
@doc """
Validates a TOTP code against a secret, respecting the strategy's grace period.
When `grace_period` is nil, calls `NimbleTOTP.valid?/3` directly.
When set to `n`, also accepts codes from the previous `n` time periods.
"""
@spec valid_totp?(binary, binary, AshAuthentication.Strategy.Totp.t(), keyword) :: boolean
def valid_totp?(secret, code, strategy, opts \\ []) do
base_opts = [period: strategy.period] ++ opts
if strategy.grace_period do
time = System.os_time(:second)
Enum.any?(0..strategy.grace_period, fn i ->
NimbleTOTP.valid?(secret, code, [{:time, time - i * strategy.period} | base_opts])
end)
else
NimbleTOTP.valid?(secret, code, base_opts)
end
end
end