diff --git a/lib/towerops/accounts.ex b/lib/towerops/accounts.ex index c349091e..88cb63c2 100644 --- a/lib/towerops/accounts.ex +++ b/lib/towerops/accounts.ex @@ -653,12 +653,12 @@ defmodule Towerops.Accounts do @doc """ Checks whether the user is in sudo mode. - The user is in sudo mode when the last authentication was done no further - than 20 minutes ago. The limit can be given as second argument in minutes. + The user is in sudo mode when the last sudo verification was done no further + than the specified minutes ago. Default is 10 minutes (pass -10 as the minutes arg). """ - def sudo_mode?(user, minutes \\ -20) + def sudo_mode?(user, minutes \\ -10) - def sudo_mode?(%User{authenticated_at: ts}, minutes) when is_struct(ts, DateTime) do + def sudo_mode?(%User{last_sudo_at: ts}, minutes) when is_struct(ts, DateTime) do DateTime.after?(ts, DateTime.add(DateTime.utc_now(), minutes, :minute)) end diff --git a/lib/towerops_web/controllers/user_sudo_controller.ex b/lib/towerops_web/controllers/user_sudo_controller.ex index 198b4168..21c112d5 100644 --- a/lib/towerops_web/controllers/user_sudo_controller.ex +++ b/lib/towerops_web/controllers/user_sudo_controller.ex @@ -54,7 +54,7 @@ defmodule ToweropsWeb.UserSudoController do case Accounts.verify_totp_only(user, totp_code) do {:ok, _verified_user} -> - # Grant sudo mode + # Grant sudo mode (updates last_sudo_at in database) case Accounts.grant_sudo_mode(user) do {:ok, _updated_user} -> # Redirect to return_to path or default diff --git a/lib/towerops_web/user_auth.ex b/lib/towerops_web/user_auth.ex index fdad2669..cf5bbe87 100644 --- a/lib/towerops_web/user_auth.ex +++ b/lib/towerops_web/user_auth.ex @@ -552,8 +552,12 @@ defmodule ToweropsWeb.UserAuth do end end - def on_mount(:require_sudo_mode, _params, _session, socket) do - user = socket.assigns.current_scope && socket.assigns.current_scope.user + def on_mount(:require_sudo_mode, _params, session, socket) do + # Force refetch user from session to ensure we have latest data (including last_sudo_at) + # We need to refetch because the user may have just verified sudo mode + scope = build_scope_from_session(session) + socket = Phoenix.Component.assign(socket, :current_scope, scope) + user = scope && scope.user case {user && Accounts.sudo_mode?(user, -10), user && Accounts.totp_enabled?(user)} do {true, _} ->