diff --git a/ajax/adblock/update_blocklist.php b/ajax/adblock/update_blocklist.php index 0084892d..46f7798e 100644 --- a/ajax/adblock/update_blocklist.php +++ b/ajax/adblock/update_blocklist.php @@ -1,6 +1,7 @@ = RASPI_SESSION_TIMEOUT ? 'session_expired' : 'active'; + +if ($status = 'session_expired') { + session_unset(); // unset all session variables + session_destroy(); // destroy the session +} + +// send response +header('Content-Type: application/json'); +header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); +header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); +header('Pragma: no-cache'); + +$response = [ + 'status' => $status, + 'last_activity' => $lastActivity, + 'session_lifetime' => $sessionLifetime +]; + +echo json_encode($response); +exit(); + diff --git a/ajax/system/sys_actions.php b/ajax/system/sys_actions.php index b5b09d10..dce18402 100644 --- a/ajax/system/sys_actions.php +++ b/ajax/system/sys_actions.php @@ -1,6 +1,7 @@ i.fas { /* Font Awesome 5 brands */ .fa-reddit { - color: #ff4500; + color: #ff4500; } .fa-twitter { - color: #55acee + color: #55acee } .fa-discord { - color: #7289da + color: #7289da } .fa-github { - color: #151b23 + color: #151b23 } @keyframes heart { @@ -332,3 +333,47 @@ button > i.fas { animation: heart 1000ms infinite; } +#modal-admin-login .modal-content { + background: radial-gradient(circle at 120% -20%, #032626, #052c2c, #073232, #0a3838, #0d3f3f, #114545, #144c4c); + align-items: center; +} + +#modal-admin-login .modal-body { + min-width: 330px; +} + +.login-brand { + color: var(--raspap-theme-color); + filter: brightness(150%); +} + +.admin-login { + color: var(--raspap-offwhite); + font-size: 1.2em +} + +.btn-admin-login { + color: var(--raspap-offwhite); + background-color: var(--raspap-theme-color); +} + +.btn-admin-login:hover { + color: var(--raspap-offwhite); + background-color: #236969; +} + +.no-right-radius { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +.btn-passwd-append { + border: 1px solid #ced4da; +} + +#passwd-toggle:active, +#passwd-toggle:hover, +#passwd-toggle:focus { + border: 1px solid #ced4da; +} + diff --git a/app/img/raspAP-logo.php b/app/img/raspAP-logo.php old mode 100644 new mode 100755 diff --git a/app/img/wg-qr-code.php b/app/img/wg-qr-code.php old mode 100644 new mode 100755 diff --git a/app/img/wifi-qr-code.php b/app/img/wifi-qr-code.php old mode 100644 new mode 100755 diff --git a/app/js/custom.js b/app/js/custom.js index c33a5d5a..a3380e15 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -671,6 +671,44 @@ window.addEventListener('load', function() { }); }, false); +let sessionCheckInterval = setInterval(checkSession, 5000); + +function checkSession() { + // skip session check if on login page + if (window.location.pathname === '/login') { + return; + } + var csrfToken = $('meta[name=csrf_token]').attr('content'); + $.post('ajax/session/do_check_session.php',{'csrf_token': csrfToken},function (data) { + if (data.status === 'session_expired') { + clearInterval(sessionCheckInterval); + showSessionExpiredModal(); + } + }).fail(function (jqXHR, status, err) { + console.error("Error checking session status:", status, err); + }); +} + +function showSessionExpiredModal() { + $('#sessionTimeoutModal').modal('show'); +} + +$(document).on("click", "#js-session-expired-login", function(e) { + const loginModal = $('#modal-admin-login'); + const redirectUrl = window.location.pathname; + window.location.href = `/login?action=${encodeURIComponent(redirectUrl)}`; +}); + +// show modal login on page load +$(document).ready(function () { + const params = new URLSearchParams(window.location.search); + const redirectUrl = $('#redirect-url').val() || params.get('action') || '/'; + $('#modal-admin-login').modal('show'); + $('#redirect-url').val(redirectUrl); + $('#username').focus(); + $('#username').addClass("focusedInput"); +}); + // DHCP or Static IP option group $('#chkstatic').on('change', function() { if (this.checked) { diff --git a/config/config.php b/config/config.php index 2950632d..17c40cb4 100755 --- a/config/config.php +++ b/config/config.php @@ -1,6 +1,7 @@ isLogged()) { - if ($auth->login($user, $pass)) { - $config = $auth->getAuthConfig(); - } else { - $auth->authenticate(); - } + $auth->authenticate(); } } + diff --git a/includes/csrf.php b/includes/csrf.php index bca935df..4e098e5b 100755 --- a/includes/csrf.php +++ b/includes/csrf.php @@ -1,7 +1,6 @@ 'RaspAP', + 'RASPI_BRAND_TITLE' => RASPI_BRAND_TEXT.' Admin Panel', 'RASPI_VERSION' => '3.2.4', 'RASPI_CONFIG_NETWORK' => RASPI_CONFIG.'/networking/defaults.json', 'RASPI_CONFIG_PROVIDERS' => 'config/vpn-providers.json', @@ -16,6 +17,7 @@ $defaults = [ 'RASPI_ERROR_LOG' => sys_get_temp_dir() . '/raspap_error.log', 'RASPI_DEBUG_LOG' => 'raspap_debug.log', 'RASPI_LOG_SIZE_LIMIT' => 64, + 'RASPI_SESSION_TIMEOUT' => 1440, // Constants for configuration file paths. // These are typical for default RPi installs. Modify if needed. diff --git a/includes/footer.php b/includes/footer.php old mode 100644 new mode 100755 index 38965fc6..b12c0f1c --- a/includes/footer.php +++ b/includes/footer.php @@ -1,4 +1,6 @@ -
+ + +
v | Created by the RaspAP Team @@ -8,3 +10,19 @@
+ + diff --git a/includes/functions.php b/includes/functions.php index 3099defc..bb63c1ee 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -1,3 +1,4 @@ + login($username, $password)) { + $config = $auth->getAuthConfig(); + header('Location: ' . $redirectUrl); + die(); + } else { + $status = "Login failed"; + } + } + } + + echo renderTemplate( + "login", compact( + "status", + "redirectUrl" + ) + ); +} + diff --git a/includes/page_actions.php b/includes/page_actions.php index 2e406bf8..c9649792 100755 --- a/includes/page_actions.php +++ b/includes/page_actions.php @@ -70,6 +70,9 @@ function handleCorePageAction(string $page, array &$extraFooterScripts): void case "/about": DisplayAbout(); break; + case "/login": + DisplayLogin(); + break; default: DisplayDashboard($extraFooterScripts); } diff --git a/includes/restapi.php b/includes/restapi.php old mode 100644 new mode 100755 diff --git a/includes/session.php b/includes/session.php index fe447f3d..12e45fec 100755 --- a/includes/session.php +++ b/includes/session.php @@ -3,3 +3,8 @@ if (session_status() == PHP_SESSION_NONE) { session_start(); } + +if (!isset($_SESSION['lastActivity'])) { + $_SESSION['lastActivity'] = time(); +} + diff --git a/index.php b/index.php index c1d39e94..32c86af9 100755 --- a/index.php +++ b/index.php @@ -23,6 +23,7 @@ * as you leave these references intact in the header comments of your source files. */ +require 'includes/session.php'; require 'includes/csrf.php'; ensureCSRFSessionToken(); @@ -35,6 +36,7 @@ require_once 'includes/functions.php'; // Default page actions require_once 'includes/dashboard.php'; +require_once 'includes/login.php'; require_once 'includes/authenticate.php'; require_once 'includes/admin.php'; require_once 'includes/dhcp.php'; @@ -63,7 +65,7 @@ initializeApp(); - <?php echo _("RaspAP WiFi Configuration Portal"); ?> + <?php echo RASPI_BRAND_TITLE; ?> @@ -96,6 +98,7 @@ initializeApp(); +
@@ -123,6 +126,7 @@ initializeApp();
+ diff --git a/locale/en_US/LC_MESSAGES/messages.mo b/locale/en_US/LC_MESSAGES/messages.mo index fd8a0a65..d1c38e1f 100644 Binary files a/locale/en_US/LC_MESSAGES/messages.mo and b/locale/en_US/LC_MESSAGES/messages.mo differ diff --git a/locale/en_US/LC_MESSAGES/messages.po b/locale/en_US/LC_MESSAGES/messages.po index 95fa1281..8a9c0a63 100644 --- a/locale/en_US/LC_MESSAGES/messages.po +++ b/locale/en_US/LC_MESSAGES/messages.po @@ -1566,3 +1566,23 @@ msgstr "Restarting restapi.service" msgid "Information provided by restapi.service" msgstr "Information provided by restapi.service" +#: includes/login.php + +msgid "Session Expired" +msgstr "Session Expired" + +msgid "Your session has expired. Please login to continue." +msgstr "Your session has expired. Please login to continue." + +msgid "Login" +msgstr "Login" + +msgid "Administrator login" +msgstr "Administrator login" + +msgid "Forgot password" +msgstr "Forgot password" + +msgid "Login failed" +msgstr "Login failed" + diff --git a/src/RaspAP/Auth/HTTPAuth.php b/src/RaspAP/Auth/HTTPAuth.php index 9751075f..d32a36ad 100755 --- a/src/RaspAP/Auth/HTTPAuth.php +++ b/src/RaspAP/Auth/HTTPAuth.php @@ -15,12 +15,6 @@ namespace RaspAP\Auth; class HTTPAuth { - - /** - * @var string $realm - */ - public $realm = 'Authentication Required'; - /** * Stored login credentials * @var array $auth_config @@ -57,15 +51,11 @@ class HTTPAuth public function authenticate() { if (!$this->isLogged()) { - header('HTTP/1.0 401 Unauthorized'); - header('WWW-Authenticate: Basic realm="'.$this->realm.'"'); - if (function_exists('http_response_code')) { - // http_response_code will respond with proper HTTP version - http_response_code(401); - } else { - header('HTTP/1.0 401 Unauthorized'); + $redirectUrl = $_SERVER['REQUEST_URI']; + if (strpos($redirectUrl, '/login') === false) { + header('Location: /login?action=' . urlencode($redirectUrl)); + exit(); } - exit('Not authorized'.PHP_EOL); } } diff --git a/templates/login.php b/templates/login.php new file mode 100755 index 00000000..57207245 --- /dev/null +++ b/templates/login.php @@ -0,0 +1,42 @@ + + + diff --git a/templates/restapi.php b/templates/restapi.php old mode 100644 new mode 100755