Merge branch 'master' into feat/plugin-manager

This commit is contained in:
Bill Zimmerman 2025-01-26 10:33:49 +01:00 committed by GitHub
commit a619e7a25b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 335 additions and 75 deletions

View File

@ -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.

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require_once '../../includes/config.php';
require_once '../../includes/session.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/session.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../src/RaspAP/Parsers/IwParser.php';

View File

@ -1,7 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/functions.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -0,0 +1,32 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';
$lastActivity = $_SESSION['lastActivity'] ?? time();
$sessionLifetime = time() - $lastActivity;
$status = $sessionLifetime >= 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();

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/defaults.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -1,6 +1,7 @@
<?php
require_once '../../includes/config.php';
require_once '../../includes/session.php';
require_once '../../src/RaspAP/Auth/HTTPAuth.php';
require_once '../../includes/authenticate.php';

View File

@ -10,6 +10,7 @@ License: GNU General Public License v3.0
--raspap-content-main: #495057;
--raspap-text-muted: #858796;
--raspap-brand-color: #2b8080;
--raspap-offwhite: #faf9f6;
}
a {
@ -306,16 +307,16 @@ button > 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;
}

0
app/img/raspAP-logo.php Normal file → Executable file
View File

0
app/img/wg-qr-code.php Normal file → Executable file
View File

0
app/img/wifi-qr-code.php Normal file → Executable file
View File

View File

@ -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) {

View File

@ -1,6 +1,7 @@
<?php
define('RASPI_BRAND_TEXT', 'RaspAP');
define('RASPI_BRAND_TITLE', RASPI_BRAND_TEXT.' Admin Panel');
define('RASPI_CONFIG', '/etc/raspap');
define('RASPI_CONFIG_NETWORK', RASPI_CONFIG.'/networking/defaults.json');
define('RASPI_CONFIG_PROVIDERS', 'config/vpn-providers.json');
@ -11,6 +12,7 @@ define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
define('RASPI_ERROR_LOG', sys_get_temp_dir() . '/raspap_error.log');
define('RASPI_DEBUG_LOG', 'raspap_debug.log');
define('RASPI_LOG_SIZE_LIMIT', 64);
define('RASPI_SESSION_TIMEOUT', 1440);
// Constants for configuration file paths.
// These are typical for default RPi installs. Modify if needed.

View File

@ -1,16 +1,10 @@
<?php
if (RASPI_AUTH_ENABLED) {
$user = $_SERVER['PHP_AUTH_USER'] ?? '';
$pass = $_SERVER['PHP_AUTH_PW'] ?? '';
$auth = new \RaspAP\Auth\HTTPAuth;
if (!$auth->isLogged()) {
if ($auth->login($user, $pass)) {
$config = $auth->getAuthConfig();
} else {
$auth->authenticate();
}
$auth->authenticate();
}
}

View File

@ -1,7 +1,6 @@
<?php
require_once 'functions.php';
require_once 'session.php';
if (csrfValidateRequest() && !CSRFValidate()) {
handleInvalidCSRFToken();

View File

@ -6,7 +6,8 @@ if (!defined('RASPI_CONFIG')) {
$defaults = [
'RASPI_BRAND_TEXT' => '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.

View File

@ -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);

View File

@ -1,4 +1,6 @@
<div class="d-flex align-items-center justify-content-between small">
<?php $_SESSION['lastActivity'] = time(); ?>
<div class="d-flex align-items-center justify-content-between small">
<div class="text-muted">
<span class="pe-2"><a href="/about">v<?php echo RASPI_VERSION; ?></a></span> |
<span class="ps-2">Created by the <a href="https://github.com/RaspAP" target="_blank" rel="noopener">RaspAP Team</a></span>
@ -8,3 +10,19 @@
</div>
</div>
<div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="sessionTimeoutModal" tabindex="-1" aria-labelledby="sessionTimeoutLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title" id="sessionTimeoutLabel"><i class="fa fa-clock me-2"></i><?php echo _("Session Expired"); ?></div>
</div>
<div class="modal-body">
<?php echo _("Your session has expired. Please login to continue.") ?>
</div>
<div class="modal-footer">
<button type="button" id="js-session-expired-login" class="btn btn-outline btn-primary"><?php echo _("Login"); ?></button>
</div>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
<?php require_once 'session.php'; ?>
<?php
/* Functions for Networking */
@ -336,23 +337,26 @@ function CSRFMetaTag()
*/
function CSRFValidate()
{
if(isset($_POST['csrf_token'])) {
$post_token = $_POST['csrf_token'];
$header_token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;
if (empty($_SESSION['csrf_token']) || !is_string($_SESSION['csrf_token'])) {
error_log('Session expired or CSRF token is missing.');
header('Location: /login');
exit;
}
if (empty($post_token) && is_null($header_token)) {
return false;
}
$request_token = $post_token;
if (empty($post_token)) {
$request_token = $header_token;
}
if (hash_equals($_SESSION['csrf_token'], $request_token)) {
return true;
} else {
error_log('CSRF violation');
return false;
}
$post_token = $_POST['csrf_token'] ?? null;
$header_token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;
if (empty($post_token) && is_null($header_token)) {
error_log('CSRF token missing in the request');
return false;
}
$request_token = $post_token ?: $header_token;
if (hash_equals($_SESSION['csrf_token'], $request_token)) {
return true;
} else {
error_log('CSRF token mismatch');
return false;
}
}

40
includes/login.php Executable file
View File

@ -0,0 +1,40 @@
<?php
require_once 'includes/config.php';
require_once 'includes/functions.php';
/**
* Handler for administrative user login
*/
function DisplayLogin()
{
// initialize auth object
$auth = new \RaspAP\Auth\HTTPAuth;
$status = null;
$redirectUrl = null;
// handle page action
if (RASPI_AUTH_ENABLED) {
if (isset($_POST['login-auth'])) {
// authenticate user
$username = $_POST['username'];
$password = $_POST['password'];
$redirectUrl = $_POST['redirect-url'];
if ($auth->login($username, $password)) {
$config = $auth->getAuthConfig();
header('Location: ' . $redirectUrl);
die();
} else {
$status = "Login failed";
}
}
}
echo renderTemplate(
"login", compact(
"status",
"redirectUrl"
)
);
}

View File

@ -70,6 +70,9 @@ function handleCorePageAction(string $page, array &$extraFooterScripts): void
case "/about":
DisplayAbout();
break;
case "/login":
DisplayLogin();
break;
default:
DisplayDashboard($extraFooterScripts);
}

View File

@ -3,3 +3,8 @@
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['lastActivity'])) {
$_SESSION['lastActivity'] = time();
}

View File

@ -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;
}

View File

@ -14,7 +14,7 @@
* @author Lawrence Yau <sirlagz@gmail.com>
* @author Bill Zimmerman <billzimmerman@gmail.com>
* @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();
<meta name="description" content="">
<meta name="author" content="">
<title><?php echo _("RaspAP WiFi Configuration Portal"); ?></title>
<title><?php echo RASPI_BRAND_TITLE; ?></title>
<!-- Bootstrap Core CSS -->
<link href="dist/bootstrap/css/bootstrap.min.css" rel="stylesheet">
@ -96,6 +98,7 @@ initializeApp();
<body class="sb-nav-fixed">
<!-- Navbar -->
<?php ob_start(); ?>
<?php require_once 'includes/navbar.php'; ?>
<!-- End of Navbar -->
<div id="layoutSidenav">
@ -123,6 +126,7 @@ initializeApp();
</footer>
</div>
</div>
<?php ob_end_flush(); ?>
<!-- jQuery -->
<script src="dist/jquery/jquery.min.js"></script>

View File

@ -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"

View File

@ -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);
}
}

View File

@ -30,10 +30,8 @@
<option disabled="disabled"></option>
<?php echo optionsForSelect(blocklistProviders()) ?>
</select>
<div class="input-group-append">
<button class="btn btn-sm btn-outline-secondary rounded-end" type="button" onclick="updateBlocklist()"><?php echo _("Update now"); ?></button>
<span id="cbxblocklist-status" class="input-group-addon check-hidden ms-2 mt-1"><i class="fas fa-check"></i></span>
</div>
<button class="btn btn-sm btn-outline-secondary rounded-end" type="button" onclick="updateBlocklist()"><?php echo _("Update now"); ?></button>
<span id="cbxblocklist-status" class="input-group-addon check-hidden ms-2 mt-1"><i class="fas fa-check"></i></span>
</div>
</div>
</div>

42
templates/login.php Executable file
View File

@ -0,0 +1,42 @@
<!-- fullscreen modal -->
<div class="modal" id="modal-admin-login" data-bs-backdrop="static" data-bs-keyboard="false" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row h-100 justify-content-center align-items-center">
<div class="col-12">
<!-- branding -->
<div class="text-center mb-3">
<img src="app/img/raspAP-logo.php" class="navbar-logo" alt="RaspAP logo" class="img-fluid" style="max-width: 100px;">
<h2 class="login-brand"><?php echo htmlspecialchars(RASPI_BRAND_TEXT); ?></h2>
<div class="mt-2 admin-login"><?php echo _("Administrator login") ?></div>
<div class="text-center text-danger mt-1 mb-3"><?php echo $status ?></div>
</div>
<div class="text-center mb-4">
<form id="admin-login-form" action="login" method="POST" class="needs-validation" novalidate>
<?php echo CSRFTokenFieldTag() ?>
<div class="form-group">
<input type="hidden" name="login-auth">
<input type="hidden" id="redirect-url" name="redirect-url" value="<?php echo htmlspecialchars($redirectUrl, ENT_QUOTES, 'UTF-8'); ?>">
<input type="text" class="form-control" id="username" name="username" placeholder="<?php echo _("Username") ?>" required>
</div>
<div class="mt-2">
<div class="input-group has-validation">
<input type="password" class="form-control rounded-start border-end-0 no-right-radius" id="password" name="password" placeholder="<?php echo _("Password") ?>" required>
<button class="btn bg-white btn-passwd-append border-start-0 js-toggle-password" type="button" id="passwd-toggle" data-bs-target="[name=password]" data-toggle-with="fas fa-eye-slash text-secondary text-opacity-50">
<i class="fas fa-eye text-secondary text-opacity-50"></i>
</button>
</div>
</div>
<button type="submit" class="btn btn-outline btn-admin-login rounded-pill w-75 mt-4"><?php echo _("Login") ?></button>
<div class="small mt-2"><a href="https://docs.raspap.com/authentication/#restoring-defaults" target="_blank"><?php echo _("Forgot password") ?></a></div>
</form>
</div>
</div><!-- /.col -->
</div><!-- /.row -->
</div><!-- /.modal-body -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>

0
templates/restapi.php Normal file → Executable file
View File

View File

@ -21,10 +21,8 @@
</div>
<div class="input-group col-md-12">
<input type="text" class="form-control" name="wg-peer" id="wg-peerpubkey" value="<?php echo htmlspecialchars($wg_peerpubkey, ENT_QUOTES); ?>" />
<div class="input-group-append">
<button class="btn btn-outline-secondary rounded-end wg-keygen" type="button"><i class="fas fa-magic"></i></button>
<span id="wg-peer-pubkey-status" class="input-group-addon check-hidden ms-2 mt-1"><i class="fas fa-check"></i></span>
</div>
<div class="btn btn-outline-secondary rounded-end wg-keygen"><i class="fa-solid fa-wand-magic-sparkles"></i></div>
<span id="wg-peer-pubkey-status" class="input-group-addon check-hidden ms-2 mt-1"><i class="fas fa-check"></i></span>
</div>
</div>