1
0
mirror of https://github.com/billz/raspap-webgui.git synced 2025-07-09 23:37:41 +02:00

Refactor DisplayDashboard()

This commit is contained in:
billz 2025-03-17 04:04:27 -07:00
parent 339437f47f
commit 93395a8aa5

View File

@ -7,187 +7,249 @@ require_once 'includes/functions.php';
/** /**
* Displays the dashboard * Displays the dashboard
*/ */
function DisplayDashboard() function DisplayDashboard(): void
{ {
// instantiate RaspAP objects // instantiate RaspAP objects
$status = new \RaspAP\Messages\StatusMessage; $status = new \RaspAP\Messages\StatusMessage;
$system = new \RaspAP\System\Sysinfo; $system = new \RaspAP\System\Sysinfo;
$pluginManager = \RaspAP\Plugins\PluginManager::getInstance(); $pluginManager = \RaspAP\Plugins\PluginManager::getInstance();
// set AP and client interface session vars
getWifiInterface();
$interface = $_SESSION['ap_interface'] ?? 'wlan0';
$clientInterface = $_SESSION['wifi_client_interface'];
$hostname = $system->hostname(); $hostname = $system->hostname();
$revision = $system->rpiRevision(); $revision = $system->rpiRevision();
$hostapd = $system->hostapdStatus(); $hostapd = $system->hostapdStatus();
$adblock = $system->adBlockStatus(); $adblock = $system->adBlockStatus();
$vpn = $system->getActiveVpnInterface();
$frequency = getFrequencyBand($interface);
$details = getInterfaceDetails($interface);
$wireless = getWirelessDetails($interface);
$connectedBSSID = getConnectedBSSID($interface);
$state = strtolower($details['state']);
$plugins = $pluginManager->getInstalledPlugins();
getWifiInterface();
exec('ip a show '.$_SESSION['ap_interface'], $stdoutIp);
$stdoutIpAllLinesGlued = implode(" ", $stdoutIp);
$stdoutIpWRepeatedSpaces = preg_replace('/\s\s+/', ' ', $stdoutIpAllLinesGlued);
preg_match('/link\/ether ([0-9a-f:]+)/i', $stdoutIpWRepeatedSpaces, $matchesMacAddr) || $matchesMacAddr[1] = _('No MAC Address Found');
$macAddr = $matchesMacAddr[1];
$ipv4Addrs = '';
$ipv4Netmasks = '';
if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $stdoutIpWRepeatedSpaces, $matchesIpv4AddrAndSubnet, PREG_SET_ORDER)) {
$ipv4Addrs = _('None');
} else {
foreach ($matchesIpv4AddrAndSubnet as $inet) {
$address = $inet[1];
$suffix = (int) $inet[2];
$netmask = long2ip(-1 << (32 - $suffix));
$ipv4Addrs .= " $address";
$ipv4Netmasks .= " $netmask";
}
$ipv4Addrs = trim($ipv4Addrs);
$ipv4Netmasks = trim($ipv4Netmasks);
}
$ipv4Netmasks = empty($ipv4Netmasks) ? "-" : $ipv4Netmasks;
$ipv6Addrs = '';
if (!preg_match_all('/inet6 ([a-f0-9:]+)/i', $stdoutIpWRepeatedSpaces, $matchesIpv6Addr)) {
$ipv6Addrs = _('No IPv6 Address Found');
} else {
if (isset($matchesIpv6Addr[1])) {
$ipv6Addrs = implode(' ', $matchesIpv6Addr[1]);
}
}
preg_match('/state (UP|DOWN)/i', $stdoutIpWRepeatedSpaces, $matchesState) || $matchesState[1] = 'unknown';
$interfaceState = $matchesState[1];
define('SSIDMAXLEN', 32);
exec('iw dev ' .$_SESSION['ap_interface']. ' info ', $stdoutIw);
$stdoutIwAllLinesGlued = implode('+', $stdoutIw);
$stdoutIwWRepSpaces = preg_replace('/\s\s+/', ' ', $stdoutIwAllLinesGlued);
preg_match('/Connected to (([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2}))/', $stdoutIwWRepSpaces, $matchesBSSID) || $matchesBSSID[1] = '';
$connectedBSSID = $matchesBSSID[1];
$connectedBSSID = empty($connectedBSSID) ? "-" : $connectedBSSID;
$wlanHasLink = false;
if ($interfaceState === 'UP') {
$wlanHasLink = true;
}
if (!preg_match('/SSID: ([^+]{1,'.SSIDMAXLEN.'})/', $stdoutIwWRepSpaces, $matchesSSID)) {
$wlanHasLink = false;
$matchesSSID[1] = 'None';
}
$connectedSSID = str_replace('\x20', '', $matchesSSID[1]);
preg_match('/freq: (\d+)/i', $stdoutIwWRepSpaces, $matchesFrequency) || $matchesFrequency[1] = '';
$frequency = $matchesFrequency[1].' MHz';
preg_match('/signal: (-?[0-9]+ dBm)/i', $stdoutIwWRepSpaces, $matchesSignal) || $matchesSignal[1] = '';
$signalLevel = $matchesSignal[1];
$signalLevel = empty($signalLevel) ? "-" : $signalLevel;
preg_match('/tx bitrate: ([0-9\.]+ [KMGT]?Bit\/s)/', $stdoutIwWRepSpaces, $matchesBitrate) || $matchesBitrate[1] = '';
$bitrate = $matchesBitrate[1];
$bitrate = empty($bitrate) ? "-" : $bitrate;
// txpower is now displayed on iw dev(..) info command, not on link command.
exec('iw dev '.$_SESSION['wifi_client_interface'].' info ', $stdoutIwInfo);
$stdoutIwInfoAllLinesGlued = implode(' ', $stdoutIwInfo);
$stdoutIpInfoWRepSpaces = preg_replace('/\s\s+/', ' ', $stdoutIwInfoAllLinesGlued);
preg_match('/txpower ([0-9\.]+ dBm)/i', $stdoutIpInfoWRepSpaces, $matchesTxPower) || $matchesTxPower[1] = '';
$txPower = $matchesTxPower[1];
$strLinkQuality = 0;
if ($signalLevel > -100 && $wlanHasLink) {
if ($signalLevel >= 0) {
$strLinkQuality = 100;
} else {
$strLinkQuality = 100 + intval($signalLevel);
}
}
$wlan0up = false;
$classMsgDevicestatus = 'warning';
if ($interfaceState === 'UP') {
$wlan0up = true;
$classMsgDevicestatus = 'success';
}
if (!RASPI_MONITOR_ENABLED) {
if (isset($_POST['ifdown_wlan0'])) {
// Pressed stop button
if ($interfaceState === 'UP') {
$status->addMessage(sprintf(_('Interface is going %s.'), _('down')), 'warning');
exec('sudo ip link set '.$_SESSION['ap_interface'].' down');
$wlan0up = false;
$status->addMessage(sprintf(_('Interface is now %s.'), _('down')), 'success');
} elseif ($interfaceState === 'unknown') {
$status->addMessage(_('Interface state unknown.'), 'danger');
} else {
$status->addMessage(sprintf(_('Interface already %s.'), _('down')), 'warning');
}
} elseif (isset($_POST['ifup_wlan0'])) {
// Pressed start button
if ($interfaceState === 'DOWN') {
$status->addMessage(sprintf(_('Interface is going %s.'), _('up')), 'warning');
exec('sudo ip link set ' .$_SESSION['ap_interface']. ' up');
exec('sudo ip -s a f label ' .$_SESSION['ap_interface']);
$wlan0up = true;
$status->addMessage(sprintf(_('Interface is now %s.'), _('up')), 'success');
} elseif ($interfaceState === 'unknown') {
$status->addMessage(_('Interface state unknown.'), 'danger');
} else {
$status->addMessage(sprintf(_('Interface already %s.'), _('up')), 'warning');
}
} else {
$status->addMessage(sprintf(_('Interface is %s.'), strtolower($interfaceState)), $classMsgDevicestatus);
}
}
$arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini');
$bridgedEnable = $arrHostapdConf['BridgedEnable']; $bridgedEnable = $arrHostapdConf['BridgedEnable'];
$clientInterface = $_SESSION['wifi_client_interface'];
$apInterface = $_SESSION['ap_interface'];
$MACPattern = '"([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}"';
if (getBridgedState()) { // handle page actions
$moreLink = "hostapd_conf"; if (!empty($_POST)) {
exec('iw dev ' . $apInterface . ' station dump | grep -oE ' . $MACPattern, $clients); $status = handlePageAction($state, $_POST, $status, $interface);
} else { // refresh interface details + state
$moreLink = "dhcpd_conf"; $details = getInterfaceDetails($interface);
exec('cat ' . RASPI_DNSMASQ_LEASES . '| grep -E $(iw dev ' . $apInterface . ' station dump | grep -oE ' . $MACPattern . ' | paste -sd "|")', $clients); $state = strtolower($details['state']);
} }
$ifaceStatus = $wlan0up ? "up" : "down";
$plugins = $pluginManager->getInstalledPlugins(); $ipv4Address = $details['ipv4'];
$ipv4Netmask = $details['ipv4_netmask'];
$macAddress = $details['mac'];
$ssid = $wireless['ssid'];
$bridgedStatus = ($bridgedEnable == 1) ? "active" : ""; $bridgedStatus = ($bridgedEnable == 1) ? "active" : "";
$hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $hostapdStatus = ($hostapd[0] == 1) ? "active" : "";
$adblockStatus = ($adblock == true) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : "";
$varName = "freq" . str_replace('.', '', $frequency) . "active";
$$varName = "active";
$vpnStatus = $vpn ? "active" : "inactive";
if ($vpn) {
$vpnManaged = getVpnManged($vpn);
}
$firewallInstalled = array_filter($plugins, fn($p) => str_ends_with($p, 'Firewall')) ? true : false; $firewallInstalled = array_filter($plugins, fn($p) => str_ends_with($p, 'Firewall')) ? true : false;
if (!$firewallInstalled) { if (!$firewallInstalled) {
$firewallStack = '<i class="fas fa-slash fa-stack-1x"></i>'; $firewallUnavailable = '<i class="fas fa-slash fa-stack-1x"></i>';
} }
echo renderTemplate( echo renderTemplate(
"dashboard", compact( "dashboard", compact(
"clients", "clients",
"moreLink", "interface",
"apInterface",
"clientInterface", "clientInterface",
"ifaceStatus", "state",
"bridgedStatus", "bridgedStatus",
"hostapdStatus", "hostapdStatus",
"adblockStatus", "adblockStatus",
"firewallStack", "vpnStatus",
"vpnManaged",
"firewallUnavailable",
"status", "status",
"ipv4Addrs", "ipv4Address",
"ipv4Netmasks", "ipv4Netmask",
"ipv6Addrs", "ipv6Address",
"macAddr", "macAddress",
"connectedSSID", "ssid",
"connectedBSSID", "bssid",
"frequency", "frequency",
"revision", "freq5active",
"wlan0up" "freq24active",
"revision"
) )
); );
} }
/*
* Returns the management page for an associated VPN
*
* @param string $interface
* @return string
* @todo Determine if VPN provider is active
*/
function getVpnManged(?string $interface = null): ?string
{
return match ($interface) {
'wg0' => 'wg_conf',
'tun0' => 'openvpn_conf',
'tailscale0' => 'plugin__Tailscale',
default => null,
};
}
/*
* Parses output of iw, extracts frequency (MHz) and classifies
* it as 2.4 or 5 GHz. Returns null if not found
*
* @param string $interface
* @return string frequency
*/
function getFrequencyBand(string $interface): ?string
{
$output = shell_exec("iw dev " . escapeshellarg($interface) . " info 2>/dev/null");
if (!$output) {
return null;
}
if (preg_match('/channel\s+\d+\s+\((\d+)\s+MHz\)/', $output, $matches)) {
$frequency = (int)$matches[1];
if ($frequency >= 2400 && $frequency < 2500) {
return "2.4";
} elseif ($frequency >= 5000 && $frequency < 6000) {
return "5";
}
}
return null;
}
/*
* Aggregate function that fetches output of ip and calls
* functions to parse output into discreet network properties
*
* @param string $interface
* @return array
*/
function getInterfaceDetails(string $interface): array {
$output = shell_exec('ip a show ' . escapeshellarg($interface));
if (!$output) {
return [
'mac' => _('No MAC Address Found'),
'ipv4' => 'None',
'ipv4_netmask' => '-',
'ipv6' => _('No IPv6 Address Found'),
'state' => 'unknown'
];
}
$cleanOutput = preg_replace('/\s\s+/', ' ', implode(' ', explode("\n", $output)));
return [
'mac' => getMacAddress($cleanOutput),
'ipv4' => getIPv4Addresses($cleanOutput),
'ipv4_netmask' => getIPv4Netmasks($cleanOutput),
'ipv6' => getIPv6Addresses($cleanOutput),
'state' => getInterfaceState($cleanOutput),
];
}
function getMacAddress(string $output): string {
return preg_match('/link\/ether ([0-9a-f:]+)/i', $output, $matches) ? $matches[1] : _('No MAC Address Found');
}
function getIPv4Addresses(string $output): string {
if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) {
return 'None';
}
$addresses = array_column($matches, 1);
return implode(' ', $addresses);
}
function getIPv4Netmasks(string $output): string {
if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) {
return '-';
}
$netmasks = array_map(fn($match) => long2ip(-1 << (32 - (int)$match[2])), $matches);
return implode(' ', $netmasks);
}
function getIPv6Addresses(string $output): string {
return preg_match_all('/inet6 ([a-f0-9:]+)/i', $output, $matches) && isset($matches[1])
? implode(' ', $matches[1])
: _('No IPv6 Address Found');
}
function getInterfaceState(string $output): string {
return preg_match('/state (UP|DOWN)/i', $output, $matches) ? $matches[1] : 'unknown';
}
function getWirelessDetails(string $interface): array {
$output = shell_exec('iw dev ' . escapeshellarg($interface) . ' info');
if (!$output) {
return ['bssid' => '-', 'ssid' => '-'];
}
$cleanOutput = preg_replace('/\s\s+/', ' ', trim($output)); // Fix here
return [
'bssid' => getConnectedBSSID($cleanOutput),
'ssid' => getSSID($cleanOutput),
];
}
function getConnectedBSSID(string $output): string {
return preg_match('/Connected to (([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2}))/i', $output, $matches)
? $matches[1]
: '-';
}
function getSSID(string $output): string {
return preg_match('/ssid ([^\n\s]+)/i', $output, $matches)
? $matches[1]
: '-';
}
/**
* Handles dashboard page actions
*
* @param string $state
* @param array $post
* @param object $status
* @param string $interface
*/
function handlePageAction(string $state, array $post, $status, string $interface): object
{
if (!RASPI_MONITOR_ENABLED) {
if (isset($post['ifdown_wlan0'])) {
if ($state === 'up') {
$status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('down')), 'warning');
exec('sudo ip link set ' .escapeshellarg($interface). ' down');
$status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('down')), 'success');
} elseif ($details['state'] === 'unknown') {
$status->addMessage(_('Interface state unknown'), 'danger');
} else {
$status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('down')), 'warning');
}
} elseif (isset($post['ifup_wlan0'])) {
if ($state === 'down') {
$status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('up')), 'warning');
exec('sudo ip link set ' .escapeshellarg($interface). ' up');
exec('sudo ip -s a f label ' .escapeshellarg($interface));
usleep(250000);
$status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('up')), 'success');
} elseif ($state === 'unknown') {
$status->addMessage(_('Interface state unknown'), 'danger');
} else {
$status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('up')), 'warning');
}
}
return $status;
}
}