Packages
ash_authentication_phoenix
2.12.2
3.0.0-rc.9
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.2
3.0.0-rc.1
3.0.0-rc.0
2.17.2
2.17.1
2.17.0
2.16.0
2.15.0
2.14.1
2.14.0
2.13.1
2.13.0
2.12.2
2.12.1
2.12.0
2.11.0
2.10.5
2.10.4
2.10.3
2.10.2
2.10.1
2.10.0
2.9.0
2.8.0
2.7.0
2.6.3
2.6.2
2.6.1
2.6.0
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.2
2.0.1
2.0.0
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.7
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.1
1.8.0
1.7.3
1.7.2
1.7.1
1.7.0
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.1
1.3.0
1.2.0
1.1.0
1.0.1
1.0.0
Phoenix integration for Ash Authentication
Current section
Files
Jump to
Current section
Files
lib/ash_authentication_phoenix/components/helpers.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Phoenix.Components.Helpers do
@moduledoc """
Helpers which are commonly needed inside the various components.
"""
alias Ash.Resource.Info
alias AshAuthentication.{Strategy, Strategy.RememberMe}
alias Phoenix.LiveView.Socket
require Logger
@doc """
The LiveView `Socket` contains a reference to the Phoenix endpoint, and from
there we can extract the `otp_app` of the current request.
This is pulled from `assigns[:otp_app]`, or inferred
from the socket if that is not set.
"""
@spec otp_app_from_socket(Socket.t()) :: atom
def otp_app_from_socket(socket) do
socket.assigns[:otp_app] ||
:otp_app
|> socket.endpoint.config()
end
def auth_path(socket, subject_name, auth_routes_prefix, strategy, phase, params \\ %{}) do
if auth_routes_prefix do
strategy
|> AshAuthentication.Strategy.routes()
|> Enum.find(&(elem(&1, 1) == phase))
|> elem(0)
|> URI.parse()
|> set_query(params)
|> Map.update!(:path, &Path.join(auth_routes_prefix, &1))
|> URI.to_string()
else
route_helpers = route_helpers(socket)
if Code.ensure_loaded?(route_helpers) do
route_helpers.auth_path(
socket.endpoint,
{subject_name, AshAuthentication.Strategy.name(strategy), phase},
params
)
else
raise """
Must configure the `auth_routes_prefix`, or enable router helpers.
"""
end
end
end
defp set_query(uri, params) do
if params && params != %{} do
Map.put(uri, :query, URI.encode_query(params))
else
uri
end
end
@doc """
The LiveView `Socket` contains a refererence to the Phoenix router, and from
there we can generate the name of the route helpers module.
"""
@spec route_helpers(Socket.t()) :: module
def route_helpers(socket) do
Module.concat(socket.router, Helpers)
end
@doc """
Returns the name of the remember me field name if any for the given strategy.
It does this by looking for the presence of `RememberMe.MaybeGenerateTokenPreparation`
and the name of the argument that it is expecting.
"""
@spec remember_me_field(Strategy.t()) :: atom | nil
def remember_me_field(strategy) do
with sign_in_action when not is_nil(sign_in_action) <-
Info.action(strategy.resource, strategy.sign_in_action_name),
prep_opts when not is_nil(prep_opts) <-
Enum.find_value(sign_in_action.preparations, fn
%Ash.Resource.Preparation{
preparation: {RememberMe.MaybeGenerateTokenPreparation, opts}
} ->
opts
_ ->
nil
end) do
Keyword.get(prep_opts, :arguments, :remember_me)
else
_ -> nil
end
end
@doc """
Logs all form errors when `debug_authentication_failures?` is configured to `true`
"""
def debug_form_errors(form) do
if Application.get_env(:ash_authentication, :debug_authentication_failures?) do
log =
form
|> AshPhoenix.Form.raw_errors(for_path: :all)
|> Enum.sort_by(&length(elem(&1, 0)))
|> Enum.map_join(&format_error_with_path/1)
Logger.warning(
"Encountered errors when submitting form for #{inspect(form.source.resource)}#{form.source.action.name}\n\n#{log}"
)
end
form
end
defp format_error_with_path({path, error}) do
prefix =
if path == [] do
"Errors:\n\n"
else
"Errors for path #{inspect(path)}:\n\n"
end
prefix <>
Enum.map_join(error, fn error ->
Exception.format(:error, error, stacktrace(error))
|> String.split("\n")
|> Enum.map_join("\n", &" #{&1}")
end)
end
defp stacktrace(%{stacktrace: %{stacktrace: stacktrace}}) do
stacktrace
end
defp stacktrace(_error) do
nil
end
end