diff --git a/lib/towerops_web/plugs/update_session_activity.ex b/lib/towerops_web/plugs/update_session_activity.ex index c4fcb265..eefcc881 100644 --- a/lib/towerops_web/plugs/update_session_activity.ex +++ b/lib/towerops_web/plugs/update_session_activity.ex @@ -10,9 +10,6 @@ defmodule ToweropsWeb.Plugs.UpdateSessionActivity do each session was last active. The update happens in a background task to avoid slowing down requests. """ - use Gettext, backend: ToweropsWeb.Gettext - - import Phoenix.Controller, only: [put_flash: 3, redirect: 2] import Plug.Conn alias Towerops.Accounts @@ -28,48 +25,39 @@ defmodule ToweropsWeb.Plugs.UpdateSessionActivity do @doc """ Updates the last_activity_at timestamp for the current browser session. - Checks for session inactivity timeout and logs out the user if the session - has been inactive for more than 30 minutes. + Checks for session inactivity timeout and revokes the token if the session + has been inactive for more than 30 minutes. All database work runs in a + background task so the request is not blocked. + + When a timed-out session is detected, the token is deleted so the next + request will be unauthenticated and redirected to login by the auth pipeline. Looks up the session by the token stored in the session cookie, then updates the timestamp in a background task. """ def call(conn, _opts) do case get_session(conn, :user_token) do - nil -> conn - token -> handle_session_activity(conn, token) - end - end - - # Handle session activity check and timeout - defp handle_session_activity(conn, token) do - case check_session_activity(token) do - :active -> - # Session is active, update timestamp in background - Task.start(fn -> update_session_activity(token) end) + nil -> conn - :timeout -> - # Session timed out due to inactivity - logout_inactive_session(conn, token) - - :not_found -> - # Session not found, continue normally + token -> + live_socket_id = get_session(conn, :live_socket_id) + Task.start(fn -> handle_session_activity(token, live_socket_id) end) conn end end - # Check if session is still active or has timed out - defp check_session_activity(token) do + # Runs in a background task: check activity and either touch or revoke the session + defp handle_session_activity(token, live_socket_id) do case Accounts.get_browser_session_by_token_value(token) do nil -> - :not_found + :ok session -> if session_timed_out?(session) do - :timeout + revoke_inactive_session(token, live_socket_id) else - :active + Accounts.touch_browser_session(session) end end end @@ -81,35 +69,12 @@ defmodule ToweropsWeb.Plugs.UpdateSessionActivity do inactive_seconds > @inactivity_timeout_seconds end - # Log out user due to inactivity timeout - defp logout_inactive_session(conn, token) do - # Delete the session token + # Revoke the token so the next request will be unauthenticated + defp revoke_inactive_session(token, live_socket_id) do Accounts.delete_user_session_token(token) - # Broadcast logout to LiveView socket - if live_socket_id = get_session(conn, :live_socket_id) do + if live_socket_id do ToweropsWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{}) end - - # Clear session and redirect to login - conn - |> configure_session(renew: true) - |> clear_session() - |> delete_resp_cookie("_towerops_web_user_remember_me") - |> put_flash(:info, gettext("Your session expired due to inactivity. Please log in again.")) - |> redirect(to: "/users/log-in") - |> halt() - end - - defp update_session_activity(token) do - case Accounts.get_browser_session_by_token_value(token) do - nil -> - # No browser session found (might be an old session from before this feature) - :ok - - session -> - # Update activity timestamp - Accounts.touch_browser_session(session) - end end end