diff --git a/README.md b/README.md index 59467b59..d6bff4c3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ ![](https://i.imgur.com/xeKD93p.png) -[![Release 3.2.4](https://img.shields.io/badge/release-v3.2.4-green)](https://github.com/raspap/raspap-webgui/releases) [![Awesome](https://awesome.re/badge.svg)](https://github.com/thibmaek/awesome-raspberry-pi) [![Join Insiders](https://img.shields.io/static/v1?label=Insiders&message=%E2%9D%A4&logo=GitHub&color=ff69b4)](https://github.com/sponsors/RaspAP) [![Build Status](https://app.travis-ci.com/RaspAP/raspap-webgui.svg?branch=master)](https://app.travis-ci.com/RaspAP/raspap-webgui) [![Crowdin](https://badges.crowdin.net/raspap/localized.svg)](https://crowdin.com/project/raspap) [![Twitter URL](https://img.shields.io/twitter/url?label=%40RaspAP&logoColor=%23d8224c&url=https%3A%2F%2Ftwitter.com%2Frasp_ap)](https://twitter.com/rasp_ap) [![Reddit](https://img.shields.io/badge/%2Fr%2FRaspAP-e05d44?style=flat&logo=Reddit&logoColor=white&labelColor=e05d44&color=b14835)](https://reddit.com/r/RaspAP) [![Discord](https://img.shields.io/discord/642436993451819018?color=7289DA&label=Discord&logo=discord&style=flat)](https://discord.gg/KVAsaAR) +[![Release 3.2.5](https://img.shields.io/badge/release-v3.2.5-green)](https://github.com/raspap/raspap-webgui/releases) [![Awesome](https://awesome.re/badge.svg)](https://github.com/thibmaek/awesome-raspberry-pi) [![Join Insiders](https://img.shields.io/static/v1?label=Insiders&message=%E2%9D%A4&logo=GitHub&color=ff69b4)](https://github.com/sponsors/RaspAP) [![Build Status](https://app.travis-ci.com/RaspAP/raspap-webgui.svg?branch=master)](https://app.travis-ci.com/RaspAP/raspap-webgui) [![Crowdin](https://badges.crowdin.net/raspap/localized.svg)](https://crowdin.com/project/raspap) [![Twitter URL](https://img.shields.io/twitter/url?label=%40RaspAP&logoColor=%23d8224c&url=https%3A%2F%2Ftwitter.com%2Frasp_ap)](https://twitter.com/rasp_ap) [![Reddit](https://img.shields.io/badge/%2Fr%2FRaspAP-e05d44?style=flat&logo=Reddit&logoColor=white&labelColor=e05d44&color=b14835)](https://reddit.com/r/RaspAP) [![Discord](https://img.shields.io/discord/642436993451819018?color=7289DA&label=Discord&logo=discord&style=flat)](https://discord.gg/KVAsaAR) -RaspAP is feature-rich wireless router software that _just works_ on many popular [Debian-based devices](#supported-operating-systems), including the Raspberry Pi. Our popular [Quick installer](#quick-installer) and [Docker container](#docker-support) create a known-good default configuration for all current Raspberry Pis with onboard wireless. A fully responsive, mobile-ready interface gives you control over the relevant services and networking options. Advanced DHCP settings, WireGuard and OpenVPN support, [SSL certificates](https://docs.raspap.com/ssl-quick/), security audits, [captive portal integration](https://docs.raspap.com/captive/), themes and [multilingual options](https://docs.raspap.com/translations/) are included. +RaspAP is feature-rich wireless router software that _just works_ on many popular [Debian-based devices](#supported-operating-systems), including the Raspberry Pi. Our popular [Quick installer](#quick-installer) and [Docker container](#docker-support) create a known-good default configuration for all current Raspberry Pis with onboard wireless. A fully responsive, mobile-ready interface gives you control over the relevant services and networking options. Advanced DHCP settings, WireGuard and OpenVPN support, [SSL certificates](https://docs.raspap.com/ssl/), security audits, [captive portal integration](https://docs.raspap.com/captive/), themes and [multilingual options](https://docs.raspap.com/translations/) are included. RaspAP has been featured on sites such as [Instructables](http://www.instructables.com/id/Raspberry-Pi-As-Completely-Wireless-Router/), [Adafruit](https://blog.adafruit.com/2016/06/24/raspap-wifi-configuration-portal-piday-raspberrypi-raspberry_pi/), [Raspberry Pi Weekly](https://www.raspberrypi.org/weekly/commander/) and [Awesome Raspberry Pi](https://project-awesome.org/thibmaek/awesome-raspberry-pi) and implemented in countless projects. 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,15 +333,58 @@ button > i.fas { animation: heart 1000ms infinite; } -textarea.plugin-log { - width: 100%; - height: 150px; - resize: none; - border: 1px solid #dee2e6; - border-radius: 0.25rem; - padding: 0.5rem; - background-color: #f8f9fa; - font-family: monospace; - font-size: 0.9rem; +#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; +} + +textarea.plugin-log { + width: 100%; + height: 150px; + resize: none; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + padding: 0.5rem; + background-color: #f8f9fa; + font-family: monospace; + font-size: 0.9rem; +} 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 d0b83762..842494b8 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -736,18 +736,18 @@ function clearBlocklistStatus() { $('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden'); } -// Handler for the wireguard generate key button +// Handler for the WireGuard generate key button $('.wg-keygen').click(function(){ - var entity_pub = $(this).parent('div').prev('input[type="text"]'); - var entity_priv = $(this).parent('div').next('input[type="hidden"]'); + var parentGroup = $(this).closest('.input-group'); + var entity_pub = parentGroup.find('input[type="text"]'); var updated = entity_pub.attr('name')+"-pubkey-status"; - var csrfToken = $('meta[name=csrf_token]').attr('content'); + var csrfToken = $('meta[name="csrf_token"]').attr('content'); $.post('ajax/networking/get_wgkey.php',{'entity':entity_pub.attr('name'), 'csrf_token': csrfToken},function(data){ var jsonData = JSON.parse(data); entity_pub.val(jsonData.pubkey); $('#' + updated).removeClass('check-hidden').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700); - }) -}) + }); +}); // Handler for wireguard client.conf download $('.wg-client-dl').click(function(){ @@ -784,6 +784,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_VERSION' => '3.2.4', + 'RASPI_BRAND_TITLE' => RASPI_BRAND_TEXT.' Admin Panel', + 'RASPI_VERSION' => '3.2.5', 'RASPI_CONFIG_NETWORK' => RASPI_CONFIG.'/networking/defaults.json', 'RASPI_CONFIG_PROVIDERS' => 'config/vpn-providers.json', 'RASPI_CONFIG_API' => RASPI_CONFIG.'/api', @@ -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/dhcp.php b/includes/dhcp.php index 47b8edfa..fd6a47ac 100755 --- a/includes/dhcp.php +++ b/includes/dhcp.php @@ -268,6 +268,9 @@ function updateDnsmasqConfig($iface,$status) } $config .= PHP_EOL; } + if ($_POST['dhcp-ignore'] == "1") { + $config .= 'dhcp-ignore=tag:!known'.PHP_EOL; + } file_put_contents("/tmp/dnsmasqdata", $config); $msg = file_exists(RASPI_DNSMASQ_PREFIX.$iface.'.conf') ? 'updated' : 'added'; system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_PREFIX.$iface.'.conf', $result); diff --git a/includes/footer.php b/includes/footer.php index 38965fc6..b12c0f1c 100755 --- 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 02cce1c6..4316ed5d 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/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/includes/wireguard.php b/includes/wireguard.php index ed47a6e1..2cca31db 100755 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -207,7 +207,10 @@ function SaveWireGuardConfig($status) } if (isset($_POST['wg_pendpoint']) && strlen(trim($_POST['wg_pendpoint']) >0 )) { $wg_pendpoint_seg = substr($_POST['wg_pendpoint'],0,strpos($_POST['wg_pendpoint'],':')); - if (!filter_var($wg_pendpoint_seg,FILTER_VALIDATE_IP)) { + $host_port = explode(':', $wg_pendpoint_seg); + $hostname = $host_port[0]; + if (!filter_var($hostname, FILTER_VALIDATE_IP) && + !filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) { $status->addMessage('Invalid value for endpoint address', 'danger'); $good_input = false; } diff --git a/index.php b/index.php index c1d39e94..50eeec73 100755 --- a/index.php +++ b/index.php @@ -14,7 +14,7 @@ * @author Lawrence Yau * @author Bill Zimmerman * @license GNU General Public License, version 3 (GPL-3.0) - * @version 3.2.4 + * @version 3.2.5 * @link https://github.com/RaspAP/raspap-webgui/ * @link https://raspap.com/ * @see http://sirlagz.net/2013/02/08/raspap-webgui/ @@ -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.po b/locale/en_US/LC_MESSAGES/messages.po index 022d9c41..aa887cba 100644 --- a/locale/en_US/LC_MESSAGES/messages.po +++ b/locale/en_US/LC_MESSAGES/messages.po @@ -1641,3 +1641,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/adblock/general.php b/templates/adblock/general.php index c39a8b41..ff3d16f5 100644 --- a/templates/adblock/general.php +++ b/templates/adblock/general.php @@ -30,10 +30,8 @@ -
- - -
+ + 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 diff --git a/templates/wg/peers.php b/templates/wg/peers.php index fad228c4..a625b4c9 100644 --- a/templates/wg/peers.php +++ b/templates/wg/peers.php @@ -21,10 +21,8 @@
-
- - -
+
+