mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 09:53:08 +02:00
The admin idle timeout (30 min) was refreshed only by navigations and HTMX requests. During long encoding sessions on an open form there are none, so an actively-typing admin was logged out mid-work after ~30-45 min. Add an activity-driven keepalive: - /admin/session-keepalive.php: 204 when authenticated (refreshes admin_last_activity via AdminAuth::isAuthenticated()), 401 otherwise. - admin-session-keepalive.js: marks activity only on real user input (pointer/keyboard/input/scroll/wheel/touch/focus) and pings at most once per 5 min while the tab is visible. A genuinely idle tab never pings, so the idle timeout still applies. Raise the idle window 30 min -> 4 h: for a single-/few-admin back-office whose main workflow is data entry, 30 min still kicked admins who stepped away mid-form. With the keepalive in place, 4 h means "no interaction at all", not "no navigation". Absolute timeout stays 12 h. Also fix session ID rotation, which never fired: it used `$absolute % IDLE_TIMEOUT_SECONDS === 0`, i.e. required a request to land exactly on a multiple of the interval relative to login time. Replaced with an explicit admin_last_rotation timestamp and a ROTATION_INTERVAL_SECONDS (30 min) constant decoupled from the idle timeout, so raising the idle window does not widen the fixation/replay window. Refactor AdminAuth::enforceSessionTimeout() to return bool instead of redirecting/exiting, so the keepalive endpoint can report 401 cleanly rather than letting fetch follow a redirect to the login page. Smoke test (just smoke-session-keepalive) covers activity refresh, 2 h idle accepted, rotation firing, idle rejection+destruction, and unauthenticated rejection. Docs updated.
33 lines
1.1 KiB
PHP
33 lines
1.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Admin session keepalive — lightweight liveness ping.
|
|
*
|
|
* Called periodically by admin-session-keepalive.js while an admin page stays
|
|
* open and the admin is genuinely interacting with it (typing/clicking/scrolling).
|
|
*
|
|
* Without this, `AdminAuth::enforceSessionTimeout()` only refreshed
|
|
* `admin_last_activity` on navigations and HTMX requests. An admin spending
|
|
* >IDLE_TIMEOUT_SECONDS entering data in an open form (a long encoding session)
|
|
* issued no requests and was logged out mid-work.
|
|
*
|
|
* This endpoint calls `isAuthenticated()`, which runs the same timeout
|
|
* enforcement and, on success, refreshes the activity timestamp. A truly idle
|
|
* tab never pings (the client only pings after real interaction), so the idle
|
|
* timeout still applies.
|
|
*
|
|
* Responses:
|
|
* 204 — authenticated, activity refreshed (or no password configured: dev).
|
|
* 401 — not authenticated: the client should redirect to the login page.
|
|
*/
|
|
require_once __DIR__ . '/../../bootstrap.php';
|
|
require_once __DIR__ . '/../../src/AdminAuth.php';
|
|
|
|
if (!AdminAuth::isAuthenticated()) {
|
|
http_response_code(401);
|
|
exit;
|
|
}
|
|
|
|
http_response_code(204);
|
|
exit;
|