From c53c1a27a45bd82633ba13191991885d3763dc8e Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:02:35 -0700 Subject: [PATCH 01/11] Fix: Specify global Exception class by adding backslash --- src/RaspAP/DotEnv/DotEnv.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RaspAP/DotEnv/DotEnv.php b/src/RaspAP/DotEnv/DotEnv.php index 1e8397a1..0b250f92 100644 --- a/src/RaspAP/DotEnv/DotEnv.php +++ b/src/RaspAP/DotEnv/DotEnv.php @@ -37,7 +37,7 @@ class DotEnv } } } else { - throw new Exception(".env file '{$this->envFile}' not found."); + throw new \Exception(".env file '{$this->envFile}' not found."); } } @@ -75,7 +75,7 @@ class DotEnv file_put_contents("/tmp/.env", $content); system('sudo mv /tmp/.env '.$this->envFile, $result); if ($result !== 0) { - throw new Exception("Unable to move .env file: ". $this->envFile); + throw new \Exception("Unable to move .env file: ". $this->envFile); } } @@ -83,7 +83,7 @@ class DotEnv { exec('sudo touch '. escapeshellarg($this->envFile), $output, $result); if ($result !== 0) { - throw new Exception("Unable to create .env file: ". $this->envFile); + throw new \Exception("Unable to create .env file: ". $this->envFile); } } } From 795d55a2cd2e0c3e6c162958105cd0eb7cbcb66c Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:04:00 -0700 Subject: [PATCH 02/11] Fix: Sanitize $peer_conf before output to header --- app/img/wg-qr-code.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/img/wg-qr-code.php b/app/img/wg-qr-code.php index 7a66e6fc..c487fbc1 100755 --- a/app/img/wg-qr-code.php +++ b/app/img/wg-qr-code.php @@ -13,6 +13,7 @@ if (!isset($_SERVER['HTTP_REFERER'])) { exec("sudo cat " .RASPI_WIREGUARD_PATH.'client.conf', $return); $peer_conf = implode(PHP_EOL,$return); $peer_conf.= PHP_EOL; +$peer_conf_sanitized = str_replace(["\r", "\n"], '', $peer_conf); $command = "qrencode -t svg -m 0 -o - " . mb_escapeshellarg($peer_conf); $svg = shell_exec($command); $etag = hash('sha256', $peer_conf); @@ -23,6 +24,6 @@ header("Content-Type: image/svg+xml"); header("Content-Length: $content_length"); header("Last-Modified: $last_modified"); header("ETag: \"$etag\""); -header("X-QR-Code-Content: $peer_conf"); +header("X-QR-Code-Content: $peer_conf_sanitized"); echo shell_exec($command); From a3caa6485c1ee7d046832920bfa5af6eb5afd369 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:04:40 -0700 Subject: [PATCH 03/11] Fix: Use null coalescing operator to prevent warnings --- app/img/wifi-qr-code.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/img/wifi-qr-code.php b/app/img/wifi-qr-code.php index acecfe85..19171094 100755 --- a/app/img/wifi-qr-code.php +++ b/app/img/wifi-qr-code.php @@ -12,12 +12,12 @@ if (!isset($_SERVER['HTTP_REFERER'])) { $hostapd = parse_ini_file(RASPI_HOSTAPD_CONFIG, false, INI_SCANNER_RAW); -// assume wpa encryption and get the passphrase +// assume WPA encryption and get the passphrase $type = "WPA"; $password = isset($hostapd['wpa_psk']) ? $hostapd['wpa_psk'] : $hostapd['wpa_passphrase']; -// use wep if configured -$wep_default_key = intval($hostapd['wep_default_key']); +// use WEP if configured +$wep_default_key = intval($hostapd['wep_default_key'] ?? 0); $wep_key = 'wep_key' . $wep_default_key; if (array_key_exists($wep_key, $hostapd)) { $type = "WEP"; @@ -30,7 +30,7 @@ if (empty($password)) { } $ssid = $hostapd['ssid']; -$hidden = intval($hostapd['ignore_broadcast_ssid']) != 0 ? "H:true" : ""; +$hidden = intval($hostapd['ignore_broadcast_ssid'] ?? 0) !== 0 ? "H:true" : ""; $ssid = qr_encode($ssid); $password = qr_encode($password); From d4554c6429f7a4ca80f48cb07dcd3eb6281ef1e2 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:05:11 -0700 Subject: [PATCH 04/11] Update w/ getBridgedState() global function --- includes/dashboard.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index f77c6e55..3e1b3e14 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -35,8 +35,7 @@ function DisplayDashboard(): void $ethernetClients = $dashboard->getEthernetClients(); $totalClients = $wirelessClients + $ethernetClients; $plugins = $pluginManager->getInstalledPlugins(); - $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); - $bridgedEnable = $arrHostapdConf['BridgedEnable']; + $bridgedEnable = getBridgedState(); // handle page actions if (!empty($_POST)) { From 068f363f09e8e32b678c61e00ef7009878fd9759 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:06:11 -0700 Subject: [PATCH 05/11] Remove obsolete toggleState functions, add file_exists() check --- includes/functions.php | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/includes/functions.php b/includes/functions.php index f41e1ecb..54b4939c 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -713,7 +713,6 @@ function formatDateAgo($datetime, $full = false) function initializeApp() { $_SESSION["theme_url"] = getThemeOpt(); - $_SESSION["toggleState"] = getSidebarState(); $_SESSION["bridgedEnabled"] = getBridgedState(); $_SESSION["providerID"] = getProviderID(); } @@ -739,22 +738,17 @@ function getColorOpt() return $color; } -function getSidebarState() -{ - if(isset($_COOKIE['sidebarToggled'])) { - if ($_COOKIE['sidebarToggled'] == 'true' ) { - return "toggled"; - } - } -} - -// Returns bridged AP mode status function getBridgedState() { - $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); - // defaults to false + + $hostapdIni = RASPI_CONFIG . '/hostapd.ini'; + if (!file_exists($hostapdIni)) { + return 0; + } else { + $arrHostapdConf = parse_ini_file($hostapdIni); + } return $arrHostapdConf['BridgedEnable']; -} + } // Returns VPN provider ID, if defined function getProviderID() From 16f6b7f979d90a3867ad937aadc571685091abe5 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:07:51 -0700 Subject: [PATCH 06/11] Fix numerous php warnings for undefined vars --- includes/hostapd.php | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/includes/hostapd.php b/includes/hostapd.php index 3b450996..9aad4f30 100755 --- a/includes/hostapd.php +++ b/includes/hostapd.php @@ -46,7 +46,12 @@ function DisplayHostAPDConfig() SaveHostAPDConfig($arrSecurity, $arrEncType, $arr80211Standard, $interfaces, $reg_domain, $status); } } - $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); + + $arrHostapdConf = []; + $hostapdIni = RASPI_CONFIG . '/hostapd.ini'; + if (file_exists($hostapdIni)) { + $arrHostapdConf = parse_ini_file($hostapdIni); + } if (!RASPI_MONITOR_ENABLED) { if (isset($_POST['StartHotspot']) || isset($_POST['RestartHotspot'])) { @@ -136,6 +141,9 @@ function DisplayHostAPDConfig() } } + $arrConfig['ignore_broadcast_ssid'] ??= 0; + $arrConfig['max_num_sta'] ??= 0; + $arrConfig['wep_default_key'] ??= 0; exec('sudo /bin/chmod o+r '.RASPI_HOSTAPD_LOG); $logdata = getLogLimited(RASPI_HOSTAPD_LOG); @@ -281,6 +289,15 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $reg_dom $good_input = false; } + $ignore_broadcast_ssid = $_POST['hiddenSSID'] ?? '0'; + if (!ctype_digit($ignore_broadcast_ssid)) { + $status->addMessage('Parameter hiddenSSID not a number.', 'danger'); + $good_input = false; + } elseif ((int)$ignore_broadcast_ssid < 0 || (int)$ignore_broadcast_ssid >= 3) { + $status->addMessage('Parameter hiddenSSID contains an invalid configuration value.', 'danger'); + $good_input = false; + } + /* if (isset($_POST['hiddenSSID'])) { if (!is_int((int)$_POST['hiddenSSID'])) { $status->addMessage('Parameter hiddenSSID not a number.', 'danger'); @@ -294,6 +311,7 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $reg_dom } else { $ignore_broadcast_ssid = '0'; } + */ if (! in_array($_POST['interface'], $interfaces)) { $status->addMessage('Unknown interface '.htmlspecialchars($_POST['interface'], ENT_QUOTES), 'danger'); @@ -364,14 +382,17 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $reg_dom // Set dhcp values from system config, fallback to default if undefined $jsonData = json_decode(getNetConfig($ap_iface), true); - $ip_address = ($jsonData['StaticIP'] == '') ? getDefaultNetValue('dhcp',$ap_iface,'static ip_address') : $jsonData['StaticIP']; - $domain_name_server = ($jsonData['StaticDNS'] =='') ? getDefaultNetValue('dhcp',$ap_iface,'static domain_name_server') : $jsonData['StaticDNS']; - $routers = ($jsonData['StaticRouters'] == '') ? getDefaultNetValue('dhcp',$ap_iface,'static routers') : $jsonData['StaticRouters']; - $netmask = ($jsonData['SubnetMask'] == '' || $jsonData['SubnetMask'] == '0.0.0.0') ? getDefaultNetValue('dhcp',$ap_iface,'subnetmask') : $jsonData['SubnetMask']; + $ip_address = empty($jsonData['StaticIP']) + ? getDefaultNetValue('dhcp', $ap_iface, 'static ip_address') : $jsonData['StaticIP']; + $domain_name_server = empty($jsonData['StaticDNS']) + ? getDefaultNetValue('dhcp', $ap_iface, 'static domain_name_server') : $jsonData['StaticDNS']; + $routers = empty($jsonData['StaticRouters']) + ? getDefaultNetValue('dhcp', $ap_iface, 'static routers') : $jsonData['StaticRouters']; + $netmask = (empty($jsonData['SubnetMask']) || $jsonData['SubnetMask'] === '0.0.0.0') + ? getDefaultNetValue('dhcp', $ap_iface, 'subnetmask') : $jsonData['SubnetMask']; if (isset($ip_address) && !preg_match('/.*\/\d+/', $ip_address)) { $ip_address.='/'.mask2cidr($netmask); } - if ($bridgedEnable == 1) { $config = array_keys(getDefaultNetOpts('dhcp','options')); $config[] = PHP_EOL.'# RaspAP br0 configuration'; @@ -392,7 +413,9 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $reg_dom $config[] = 'static ip_address='.$ip_address; $config[] = 'static routers='.$routers; $config[] = 'static domain_name_server='.$domain_name_server; - if (! is_null($jsonData['Metric'])) { $config[] = 'metric '.$jsonData['Metric']; } + if (!empty($jsonData['Metric'])) { + $config[] = 'metric ' . $jsonData['Metric']; + } } $dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG); From 6adeab75867464bc2fcc152008e815ae3095633c Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:08:54 -0700 Subject: [PATCH 07/11] Fix: Evaluate HTTP_ACCEPT_LANGUAGE, check ['locale'] --- includes/locale.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/includes/locale.php b/includes/locale.php index a9f07f65..9f83b5a6 100755 --- a/includes/locale.php +++ b/includes/locale.php @@ -11,7 +11,7 @@ * * Refer to: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 */ -if (empty($_SESSION['locale']) && strlen($_SERVER['HTTP_ACCEPT_LANGUAGE']) >= 2) { +if (empty($_SESSION['locale']) && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && strlen($_SERVER['HTTP_ACCEPT_LANGUAGE']) >= 2) { $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); switch ($lang) { case "de": @@ -90,9 +90,10 @@ if (empty($_SESSION['locale']) && strlen($_SERVER['HTTP_ACCEPT_LANGUAGE']) >= 2) // Use: 'sudo raspi-configure' and select 'Localisation Options' // activate the locale setting -putenv("LANG=" . $_SESSION['locale']); -setlocale(LC_ALL, $_SESSION['locale']); - +if (!empty($_SESSION['locale'])) { + putenv("LANG=" . $_SESSION['locale']); + setlocale(LC_ALL, $_SESSION['locale']); +} bindtextdomain(LOCALE_DOMAIN, LOCALE_ROOT); bind_textdomain_codeset(LOCALE_DOMAIN, 'UTF-8'); From 4e411aaa6b0c73e5b1db213f57c34afc32f4a0d0 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:09:39 -0700 Subject: [PATCH 08/11] Fix: Use null coalescing operator on user_id --- includes/navbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/navbar.php b/includes/navbar.php index 50050239..c794f64a 100755 --- a/includes/navbar.php +++ b/includes/navbar.php @@ -13,7 +13,7 @@ From f73f25708cce319954c9bd7e4b3ad649652ac121 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:10:40 -0700 Subject: [PATCH 09/11] Fix: Cleanup, resolve warnings in getWifiInterface() --- includes/wifi_functions.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/includes/wifi_functions.php b/includes/wifi_functions.php index 66217425..f55e525a 100755 --- a/includes/wifi_functions.php +++ b/includes/wifi_functions.php @@ -160,19 +160,20 @@ function sortNetworksByRSSI(&$networks) */ function getWifiInterface() { - $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); - $iface = $_SESSION['ap_interface'] = isset($arrHostapdConf['WifiInterface']) ? $arrHostapdConf['WifiInterface'] : RASPI_WIFI_AP_INTERFACE; - // check for 2nd wifi interface -> wifi client on different interface - exec("iw dev | awk '$1==\"Interface\" && $2!=\"$iface\" {print $2}'",$iface2); - $client_iface = $_SESSION['wifi_client_interface'] = (empty($iface2) ? $iface : trim($iface2[0])); + $hostapdIni = RASPI_CONFIG . '/hostapd.ini'; + $arrHostapdConf = file_exists($hostapdIni) ? parse_ini_file($hostapdIni) : []; - // specifically for rpi0W in AP-STA mode, the above check ends up with the interfaces - // crossed over (wifi_client_interface vs 'ap_interface'), because the second interface (uap0) is - // created by raspap and used as the access point. - if ($client_iface == "uap0" && ($arrHostapdConf['WifiAPEnable'] ?? 0)){ - $_SESSION['wifi_client_interface'] = $iface; - $_SESSION['ap_interface'] = $client_iface; - } + $iface = $_SESSION['ap_interface'] = $arrHostapdConf['WifiInterface'] ?? RASPI_WIFI_AP_INTERFACE; + + // check for 2nd wifi interface -> wifi client on different interface + exec("iw dev | awk '$1==\"Interface\" && $2!=\"$iface\" {print $2}'", $iface2); + $client_iface = $_SESSION['wifi_client_interface'] = empty($iface2) ? $iface : trim($iface2[0]); + + // handle special case for RPi Zero W in AP-STA mode + if ($client_iface === "uap0" && ($arrHostapdConf['WifiAPEnable'] ?? 0)) { + $_SESSION['wifi_client_interface'] = $iface; + $_SESSION['ap_interface'] = $client_iface; + } } /* From 0005488884bcda2d8fc53f90c8ef34a2e06c3867 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:12:00 -0700 Subject: [PATCH 10/11] Fix: Use null coalescing operator on $_POST object, fetch wg_log, set $peer_id --- includes/wireguard.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/includes/wireguard.php b/includes/wireguard.php index 2cca31db..f6beb3dd 100755 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -10,10 +10,10 @@ function DisplayWireGuardConfig() $status = new \RaspAP\Messages\StatusMessage; $parseFlag = true; if (!RASPI_MONITOR_ENABLED) { - $optRules = $_POST['wgRules']; - $optConf = $_POST['wgCnfOpt']; - $optSrvEnable = $_POST['wgSrvEnable']; - $optLogEnable = $_POST['wgLogEnable']; + $optRules = isset($_POST['wgRules']) ? $_POST['wgRules'] : null; + $optConf = isset($_POST['wgCnfOpt']) ? $_POST['wgCnfOpt'] : null; + $optSrvEnable = isset($_POST['wgSrvEnable']) ? $_POST['wgSrvEnable'] : null; + $optLogEnable = isset($_POST['wgLogEnable']) ? $_POST['wgLogEnable'] : null; if (isset($_POST['savewgsettings']) && $optConf == 'manual' && $optSrvEnable == 1 ) { SaveWireGuardConfig($status); } elseif (isset($_POST['savewgsettings']) && $optConf == 'upload' && is_uploaded_file($_FILES["wgFile"]["tmp_name"])) { @@ -69,6 +69,14 @@ function DisplayWireGuardConfig() $wg_state = ($wgstatus[0] == 'active' ? true : false ); $public_ip = get_public_ip(); + // retrieve wg log + $wg_log = ""; + if (file_exists('/tmp/wireguard.log')) { + exec('sudo chmod o+r /tmp/wireguard.log'); + $wg_log = file_get_contents('/tmp/wireguard.log'); + } + $peer_id = $peer_id ?? "1"; + echo renderTemplate( "wireguard", compact( "status", @@ -89,7 +97,8 @@ function DisplayWireGuardConfig() "wg_peerpubkey", "wg_pendpoint", "wg_pallowedips", - "wg_pkeepalive" + "wg_pkeepalive", + "wg_log" ) ); } From 028c0d3e06e47db71a945c2e4693035e6242f97b Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 20 Mar 2025 02:12:47 -0700 Subject: [PATCH 11/11] Move template handling of wg_log to include/wireguard --- templates/wg/logging.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/templates/wg/logging.php b/templates/wg/logging.php index 5ea440f8..26ab9e5d 100644 --- a/templates/wg/logging.php +++ b/templates/wg/logging.php @@ -8,10 +8,7 @@ aria-describedby="wgLogEnable"> - '.htmlspecialchars($log, ENT_QUOTES).''; + '.htmlspecialchars($wg_log, ENT_QUOTES).''; ?>