Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email 2fa fix - Avoid internal server error #158

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,30 @@ defmodule RecognizerWeb.Accounts.UserSettingsController do
end

def resend(conn, _params) do
conn =
conn
|> put_session(:two_factor_sent, false)
|> put_session(:two_factor_issue_time, System.system_time(:second))
user = Authentication.fetch_current_user(conn)
current_user = Accounts.get_new_two_factor_settings(user)

conn
|> put_flash(:info, "Two factor code has been resent")
|> redirect(to: Routes.user_settings_path(conn, :two_factor_init))
case current_user do
{:error, _} ->
conn
|> put_flash(:error, "Two factor setup expired or not yet initiated")
|> redirect(to: Routes.user_settings_path(conn, :edit))

{:ok, nil} ->
conn
|> put_flash(:error, "Two factor setup expired or not yet initiated")
|> redirect(to: Routes.user_settings_path(conn, :edit))

{:ok, _setting_user} ->
conn =
conn
|> put_session(:two_factor_sent, false)
|> put_session(:two_factor_issue_time, System.system_time(:second))

conn
|> put_flash(:info, "Two factor code has been resent")
|> redirect(to: Routes.user_settings_path(conn, :two_factor_init))
end
end

@doc """
Expand All @@ -49,36 +65,37 @@ defmodule RecognizerWeb.Accounts.UserSettingsController do
def two_factor_init(conn, _params) do
user = Authentication.fetch_current_user(conn)
current_user = Accounts.get_new_two_factor_settings(user)
{:ok, %{two_factor_seed: seed, notification_preference: %{two_factor: method}} = setting_user} = current_user

method_atom = normalize_to_atom(method)
case current_user do
{:error, _} ->
conn
|> put_flash(:error, "Two factor setup expired or not yet initiated")
|> redirect(to: Routes.user_settings_path(conn, :edit))

if method in [:app, "app"] do
render(conn, "confirm_two_factor.html",
barcode: Authentication.generate_totp_barcode(user, seed),
totp_app_url: Authentication.get_totp_app_url(user, seed)
)
else
conn =
if get_session(conn, :two_factor_issue_time) == nil do
put_session(conn, :two_factor_issue_time, System.system_time(:second))
else
conn
end
{:ok, nil} ->
conn
|> put_flash(:error, "Two factor setup expired or not yet initiated")
|> redirect(to: Routes.user_settings_path(conn, :edit))

two_factor_sent = get_session(conn, :two_factor_sent)
{:ok, setting_user} ->
%{two_factor_seed: seed, notification_preference: %{two_factor: method}} = setting_user

conn =
if two_factor_sent do
conn
method_atom = normalize_to_atom(method)

if method in [:app, "app"] do
render(conn, "confirm_two_factor.html",
barcode: Authentication.generate_totp_barcode(user, seed),
totp_app_url: Authentication.get_totp_app_url(user, seed)
)
else
conn = put_session(conn, :two_factor_sent, true)
current_time = System.system_time(:second)

conn = ensure_two_factor_issue_time(conn, current_time)
conn = two_factor_init_two_factor_sent(conn, setting_user, user, method_atom)

conn
|> send_two_factor_notification(setting_user, user, method_atom)
|> render("confirm_two_factor_external.html")
end

render(conn, "confirm_two_factor_external.html")
end
end

Expand Down Expand Up @@ -129,6 +146,22 @@ defmodule RecognizerWeb.Accounts.UserSettingsController do
end
end

def two_factor_init_two_factor_sent(conn, setting_user, user, method_atom) do
two_factor_sent = get_session(conn, :two_factor_sent)

conn_session =
if two_factor_sent do
conn
else
conn
|> send_two_factor_notification(setting_user, user, method_atom)

put_session(conn, :two_factor_sent, true)
end

conn_session
end

defp handle_two_factor_settings(conn, user, two_factor_code, method) do
two_factor_issue_time = get_session(conn, :two_factor_issue_time)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,38 @@ defmodule RecognizerWeb.Accounts.UserTwoFactorController do
current_user_id = get_session(conn, :two_factor_user_id)
current_user = Accounts.get_user!(current_user_id)
current_time = System.system_time(:second)
%{notification_preference: %{two_factor: two_factor_method}} = Accounts.load_notification_preferences(current_user)

conn =
if get_session(conn, :two_factor_issue_time) == nil do
conn
|> put_session(:two_factor_issue_time, current_time)
else
conn
end

two_factor_sent = get_session(conn, :two_factor_sent)
current_user = Accounts.load_notification_preferences(current_user)

case current_user do
%{notification_preference: %{two_factor: two_factor_method}} ->
conn =
if get_session(conn, :two_factor_issue_time) == nil do
conn
|> put_session(:two_factor_issue_time, current_time)
else
conn
end

two_factor_sent = get_session(conn, :two_factor_sent)

conn =
if two_factor_sent == false do
conn
|> maybe_send_two_factor_notification(current_user, two_factor_method)

conn
|> put_session(:two_factor_sent, true)
|> put_session(:two_factor_issue_time, current_time)
else
conn
end

conn =
if two_factor_sent == false do
conn
|> maybe_send_two_factor_notification(current_user, two_factor_method)
|> render("new.html", two_factor_method: two_factor_method)

conn
|> put_session(:two_factor_sent, true)
|> put_session(:two_factor_issue_time, current_time)
else
conn
end

conn
|> render("new.html", two_factor_method: two_factor_method)
_ ->
conn.redirect(to: Routes.user_session_path(conn, :new))
end
end

@doc """
Expand Down
2 changes: 1 addition & 1 deletion lib/recognizer_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ defmodule RecognizerWeb.Router do
get "/settings/two-factor/review", UserSettingsController, :review
get "/settings/two-factor", UserSettingsController, :two_factor_init
post "/settings/two-factor", UserSettingsController, :two_factor_confirm
get "/setting/two-factor/resend", UserSettingsController, :resend
get "/settings/two-factor/resend", UserSettingsController, :resend
end
end