mirror of
https://github.com/LX3JL/xlxd.git
synced 2025-12-06 07:42:01 +01:00
XSS Vulnerability Patches and Security Enhancements for Dashboard1
This commit is contained in:
parent
80821c25a3
commit
ee3f5de1de
|
|
@ -1,3 +1,99 @@
|
|||
xlx db v2.4.3
|
||||
|
||||
SECURITY UPDATE - All files updated to fix vulnerabilities
|
||||
|
||||
This release addresses multiple security vulnerabilities including XSS (Cross-Site Scripting),
|
||||
command injection, path traversal, and SSRF (Server-Side Request Forgery) attacks.
|
||||
|
||||
Files Changed and Security Fixes:
|
||||
|
||||
- "functions.php"
|
||||
* Added sanitize_output() and sanitize_attribute() helper functions for XSS prevention
|
||||
* Added validate_callsign(), validate_module(), validate_protocol() input validation functions
|
||||
* Replaced exec() call in GetSystemUptime() with secure file reading from /proc/uptime
|
||||
* Added input validation and shell argument escaping to VNStatGetData()
|
||||
* Added array bounds checking to ParseTime() to prevent errors on malformed input
|
||||
|
||||
- "class.interlink.php"
|
||||
* Added input validation to SetName() - validates reflector name format
|
||||
* Added input validation to SetAddress() - validates IP addresses and hostnames
|
||||
* Added input validation to AddModule(), RemoveModule(), and HasModuleEnabled()
|
||||
|
||||
- "class.node.php"
|
||||
* Added input validation in constructor for all parameters
|
||||
* IP addresses validated with filter_var()
|
||||
* Protocol validated against whitelist
|
||||
* Callsign format validated with regex
|
||||
* LinkedModule validated as single A-Z letter
|
||||
|
||||
- "class.parsexml.php"
|
||||
* Added element name sanitization to prevent XML injection
|
||||
* Added strip_tags() to remove HTML/XML from extracted content
|
||||
|
||||
- "class.peer.php"
|
||||
* Added input validation in constructor for all parameters
|
||||
* Same validation as class.node.php for consistency
|
||||
|
||||
- "class.reflector.php"
|
||||
* Added path traversal prevention to SetXMLFile(), SetPIDFile(), and SetFlagFile()
|
||||
* Added SSRF protection to CallHome() - blocks internal/private IP addresses
|
||||
* Added validation to ReadInterlinkFile() to prevent path traversal
|
||||
* Added XML entity encoding to PrepareInterlinkXML() and PrepareReflectorXML()
|
||||
* Added URL validation to SetCallingHome()
|
||||
* Added missing InterlinkCount(), GetInterlink(), and IsInterlinked() methods
|
||||
|
||||
- "class.station.php"
|
||||
* Added input validation in constructor for all parameters
|
||||
* Callsign format validation
|
||||
* Module validation
|
||||
|
||||
- "config.inc.php"
|
||||
* Secured external config file inclusion with path validation
|
||||
* Added realpath() checks to prevent directory traversal
|
||||
|
||||
- "modules.php"
|
||||
* All output wrapped with sanitize_output() to prevent XSS
|
||||
|
||||
- "peers.php"
|
||||
* All peer data output sanitized with sanitize_output() and sanitize_attribute()
|
||||
* URL and callsign outputs properly escaped
|
||||
|
||||
- "reflectors.php"
|
||||
* All XML element data sanitized before output
|
||||
* Dashboard URLs and reflector names properly escaped
|
||||
|
||||
- "repeaters.php"
|
||||
* Added input validation for filter parameters
|
||||
* All node/repeater data sanitized before output
|
||||
* Flag images and URLs properly escaped
|
||||
* IP addresses sanitized
|
||||
|
||||
- "traffic.php"
|
||||
* Added strict whitelist validation for interface parameter
|
||||
* Interface names validated against configured list only
|
||||
|
||||
- "users.php"
|
||||
* Added input validation for filter parameters
|
||||
* All station/user data sanitized before output
|
||||
* Callsigns, suffixes, and module names properly escaped
|
||||
|
||||
- "index.php"
|
||||
* Added secure session configuration (HttpOnly, SameSite, Secure flags)
|
||||
* Added security headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy)
|
||||
* Added whitelist validation for 'show' parameter
|
||||
* Added validation for 'do' and 'callhome' parameters
|
||||
* All configuration values sanitized before output to HTML
|
||||
* JavaScript injection prevented in page refresh code
|
||||
* All meta tags properly escaped
|
||||
|
||||
Security Vulnerabilities Fixed:
|
||||
- XSS (Cross-Site Scripting) - All user input and XML data now properly escaped
|
||||
- Command Injection - Removed unsafe exec() calls, added shell argument escaping
|
||||
- Path Traversal - File paths validated and restricted to expected directories
|
||||
- SSRF (Server-Side Request Forgery) - CallHome validates URLs and blocks internal IPs
|
||||
- Session Hijacking - Added HttpOnly, SameSite, and Secure cookie flags
|
||||
- XML Injection - Element names sanitized, content stripped of tags
|
||||
|
||||
xlx db v2.4.1
|
||||
|
||||
you can now hide the liveircddb menu button, if you are running your db in https.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
<?php
|
||||
|
||||
// Secure session configuration
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
ini_set('session.cookie_samesite', 'Strict');
|
||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
|
||||
ini_set('session.cookie_secure', 1);
|
||||
}
|
||||
|
||||
session_start();
|
||||
|
||||
// Security headers
|
||||
header("X-Content-Type-Options: nosniff");
|
||||
header("X-Frame-Options: SAMEORIGIN");
|
||||
header("X-XSS-Protection: 1; mode=block");
|
||||
header("Referrer-Policy: strict-origin-when-cross-origin");
|
||||
|
||||
if (file_exists("./pgs/functions.php")) { require_once("./pgs/functions.php"); } else { die("functions.php does not exist."); }
|
||||
if (file_exists("./pgs/config.inc.php")) { require_once("./pgs/config.inc.php"); } else { die("config.inc.php does not exist."); }
|
||||
|
||||
|
|
@ -12,6 +25,27 @@ if (!class_exists('Station')) require_once("./pgs/class.station.php");
|
|||
if (!class_exists('Peer')) require_once("./pgs/class.peer.php");
|
||||
if (!class_exists('Interlink')) require_once("./pgs/class.interlink.php");
|
||||
|
||||
// Validate 'show' parameter
|
||||
$allowed_pages = ['users', 'repeaters', 'liveircddb', 'peers', 'modules', 'reflectors', 'traffic'];
|
||||
if (!isset($_GET['show'])) {
|
||||
$_GET['show'] = '';
|
||||
} elseif (!in_array($_GET['show'], $allowed_pages, true)) {
|
||||
$_GET['show'] = '';
|
||||
}
|
||||
|
||||
// Validate 'do' parameter for filter resets
|
||||
if (isset($_GET['do']) && $_GET['do'] !== 'resetfilter') {
|
||||
unset($_GET['do']);
|
||||
}
|
||||
|
||||
// Validate 'callhome' parameter
|
||||
if (isset($_GET['callhome'])) {
|
||||
$_GET['callhome'] = filter_var($_GET['callhome'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
if ($_GET['callhome'] === null) {
|
||||
unset($_GET['callhome']);
|
||||
}
|
||||
}
|
||||
|
||||
$Reflector = new xReflector();
|
||||
$Reflector->SetFlagFile("./pgs/country.csv");
|
||||
$Reflector->SetPIDFile($Service['PIDFile']);
|
||||
|
|
@ -81,14 +115,14 @@ else {
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="description" content="<?php echo $PageOptions['MetaDescription']; ?>" />
|
||||
<meta name="keywords" content="<?php echo $PageOptions['MetaKeywords']; ?>" />
|
||||
<meta name="author" content="<?php echo $PageOptions['MetaAuthor']; ?>" />
|
||||
<meta name="revisit" content="<?php echo $PageOptions['MetaRevisit']; ?>" />
|
||||
<meta name="robots" content="<?php echo $PageOptions['MetaAuthor']; ?>" />
|
||||
<meta name="description" content="<?php echo sanitize_attribute($PageOptions['MetaDescription']); ?>" />
|
||||
<meta name="keywords" content="<?php echo sanitize_attribute($PageOptions['MetaKeywords']); ?>" />
|
||||
<meta name="author" content="<?php echo sanitize_attribute($PageOptions['MetaAuthor']); ?>" />
|
||||
<meta name="revisit" content="<?php echo sanitize_attribute($PageOptions['MetaRevisit']); ?>" />
|
||||
<meta name="robots" content="<?php echo sanitize_attribute($PageOptions['MetaRobots']); ?>" />
|
||||
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title><?php echo $Reflector->GetReflectorName(); ?> Reflector Dashboard</title>
|
||||
<title><?php echo sanitize_output($Reflector->GetReflectorName()); ?> Reflector Dashboard</title>
|
||||
<link rel="stylesheet" type="text/css" href="./css/layout.css">
|
||||
<link rel="icon" href="./favicon.ico" type="image/vnd.microsoft.icon"><?php
|
||||
|
||||
|
|
@ -99,7 +133,7 @@ else {
|
|||
var PageRefresh;
|
||||
|
||||
function ReloadPage() {
|
||||
$.get("./index.php'.(isset($_GET['show'])?'?show='.$_GET['show']:'').'", function(data) {
|
||||
$.get("./index.php'.((!empty($_GET['show'])) ? '?show='.urlencode($_GET['show']) : '').'", function(data) {
|
||||
var BodyStart = data.indexOf("<bo"+"dy");
|
||||
var BodyEnd = data.indexOf("</bo"+"dy>");
|
||||
if ((BodyStart >= 0) && (BodyEnd > BodyStart)) {
|
||||
|
|
@ -130,14 +164,14 @@ else {
|
|||
<body>
|
||||
<?php if (file_exists("./tracking.php")) { include_once("tracking.php"); }?>
|
||||
<div id="top"><img src="./img/header.jpg" alt="XLX Multiprotocol Gateway Reflector" style="margin-top:15px;" />
|
||||
<br /> <?php echo $Reflector->GetReflectorName(); ?> v<?php echo $Reflector->GetVersion(); ?> - Dashboard v<?php echo $PageOptions['DashboardVersion']; ?> <?php echo $PageOptions['CustomTXT']; ?> / Service uptime: <span id="suptime"><?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></span></div>
|
||||
<br /> <?php echo sanitize_output($Reflector->GetReflectorName()); ?> v<?php echo sanitize_output($Reflector->GetVersion()); ?> - Dashboard v<?php echo sanitize_output($PageOptions['DashboardVersion']); ?> <?php echo sanitize_output($PageOptions['CustomTXT']); ?> / Service uptime: <span id="suptime"><?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></span></div>
|
||||
<div id="menubar">
|
||||
<div id="menu">
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td><a href="./index.php" class="menulink<?php if ($_GET['show'] == '') { echo 'active'; } ?>">Users / Modules</a></td>
|
||||
<td><a href="./index.php?show=repeaters" class="menulink<?php if ($_GET['show'] == 'repeaters') { echo 'active'; } ?>">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>)</a></td>
|
||||
<td><a href="./index.php?show=peers" class="menulink<?php if ($_GET['show'] == 'peers') { echo 'active'; } ?>">Peers (<?php echo $Reflector->PeerCount(); ?>)</a></td>
|
||||
<td><a href="./index.php?show=repeaters" class="menulink<?php if ($_GET['show'] == 'repeaters') { echo 'active'; } ?>">Repeaters / Nodes (<?php echo intval($Reflector->NodeCount()); ?>)</a></td>
|
||||
<td><a href="./index.php?show=peers" class="menulink<?php if ($_GET['show'] == 'peers') { echo 'active'; } ?>">Peers (<?php echo intval($Reflector->PeerCount()); ?>)</a></td>
|
||||
<td><a href="./index.php?show=modules" class="menulink<?php if ($_GET['show'] == 'modules') { echo 'active'; } ?>">Modules list</a></td>
|
||||
<td><a href="./index.php?show=reflectors" class="menulink<?php if ($_GET['show'] == 'reflectors') { echo 'active'; } ?>">Reflectors list</a></td>
|
||||
<?php
|
||||
|
|
@ -167,7 +201,7 @@ else {
|
|||
if (!is_readable($CallingHome['HashFile']) && (!is_writeable($CallingHome['HashFile']))) {
|
||||
echo '
|
||||
<div class="error">
|
||||
your private hash in '.$CallingHome['HashFile'].' could not be created, please check your config file and the permissions for the defined folder.
|
||||
your private hash in '.sanitize_output($CallingHome['HashFile']).' could not be created, please check your config file and the permissions for the defined folder.
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
|
@ -185,7 +219,7 @@ else {
|
|||
|
||||
?>
|
||||
|
||||
<div style="width:100%;text-align:center;margin-top:50px;"><a href="mailto:<?php echo $PageOptions['ContactEmail']; ?>" style="font-family:verdana;color:#000000;font-size:12pt;text-decoration:none;"><?php echo $PageOptions['ContactEmail']; ?></a></div>
|
||||
<div style="width:100%;text-align:center;margin-top:50px;"><a href="mailto:<?php echo sanitize_attribute($PageOptions['ContactEmail']); ?>" style="font-family:verdana;color:#000000;font-size:12pt;text-decoration:none;"><?php echo sanitize_output($PageOptions['ContactEmail']); ?></a></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,16 +12,30 @@ class Interlink {
|
|||
$this->Modules = null;
|
||||
}
|
||||
|
||||
public function SetName($RefName) { $this->ReflectorName = trim($RefName); }
|
||||
public function SetAddress($RefAdd) { $this->ReflectorAddress = trim($RefAdd); }
|
||||
public function SetName($RefName) {
|
||||
$RefName = trim($RefName);
|
||||
// Validate reflector name format (XLX + 3 alphanumeric)
|
||||
if (preg_match('/^[A-Z0-9]{3,10}$/i', $RefName)) {
|
||||
$this->ReflectorName = strtoupper($RefName);
|
||||
}
|
||||
}
|
||||
public function SetAddress($RefAdd) {
|
||||
$RefAdd = trim($RefAdd);
|
||||
// Validate it's a valid hostname or IP
|
||||
if (filter_var($RefAdd, FILTER_VALIDATE_IP) ||
|
||||
filter_var($RefAdd, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
$this->ReflectorAddress = $RefAdd;
|
||||
}
|
||||
}
|
||||
public function GetName() { return $this->ReflectorName; }
|
||||
public function GetAddress() { return $this->ReflectorAddress; }
|
||||
public function GetModules() { return $this->Modules; }
|
||||
|
||||
|
||||
public function AddModule($Module) {
|
||||
$Module = trim($Module);
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1) return false;
|
||||
if (!preg_match('/^[A-Z]$/', $Module)) return false; // Only A-Z
|
||||
if (strpos($this->Modules, $Module) === false) {
|
||||
$this->Modules .= $Module;
|
||||
}
|
||||
|
|
@ -29,16 +43,20 @@ class Interlink {
|
|||
}
|
||||
|
||||
public function RemoveModule($Module) {
|
||||
$Module = trim($Module);
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1) return false;
|
||||
if (!preg_match('/^[A-Z]$/', $Module)) return false; // Only A-Z
|
||||
if (strpos($this->Modules, $Module) !== false) {
|
||||
$this->Modules = substr($this->Modules, 0, strpos($this->Modules, $Module)-1).substr($this->Modules, strpos($this->Modules, $Module)+1, strlen($this->Modules));
|
||||
$this->Modules = str_replace($Module, '', $this->Modules);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function HasModuleEnabled($Module) {
|
||||
if (strlen($Module) != 1) return false;
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1 || !preg_match('/^[A-Z]$/', $Module)) {
|
||||
return false;
|
||||
}
|
||||
return (strpos($this->Modules, $Module) !== false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,19 +14,26 @@ class Node {
|
|||
|
||||
public function __construct($Callsign, $IP, $LinkedModule, $Protocol, $ConnectTime, $LastHeardTime, $RandomID) {
|
||||
|
||||
$this->IP = $IP;
|
||||
// Validate and sanitize IP
|
||||
$IP = trim($IP);
|
||||
$this->IP = filter_var($IP, FILTER_VALIDATE_IP) ? $IP : '0.0.0.0';
|
||||
|
||||
// Validate protocol
|
||||
$Protocol = trim($Protocol);
|
||||
$allowed_protocols = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS'];
|
||||
$this->Protocol = in_array($Protocol, $allowed_protocols, true) ? $Protocol : 'Unknown';
|
||||
|
||||
$this->Protocol = $Protocol;
|
||||
$this->ConnectTime = ParseTime($ConnectTime);
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
|
||||
$this->FullCallsign = trim(str_replace(" ", "-", $Callsign));
|
||||
$this->FullCallsign = str_replace(" ", "-", $this->FullCallsign);
|
||||
$this->FullCallsign = str_replace(" ", "-", $this->FullCallsign);
|
||||
// Sanitize callsign (remove excessive spaces, validate format)
|
||||
$Callsign = trim(preg_replace('/\s+/', ' ', $Callsign));
|
||||
|
||||
$this->FullCallsign = str_replace(" ", "-", $Callsign);
|
||||
|
||||
if (strpos($Callsign, " ") !== false) {
|
||||
$this->Callsign = trim(substr($Callsign, 0, strpos($Callsign, " ")));
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " "), strlen($Callsign)));
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " ")));
|
||||
$this->Prefix = strtoupper(trim(substr($Callsign, 0, 3)));
|
||||
}
|
||||
else {
|
||||
|
|
@ -35,7 +42,15 @@ class Node {
|
|||
$this->Prefix = "";
|
||||
}
|
||||
|
||||
$this->LinkedModule = trim($LinkedModule);
|
||||
// Validate callsign format (basic check)
|
||||
if (!preg_match('/^[A-Z0-9]{1,10}$/i', $this->Callsign)) {
|
||||
$this->Callsign = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate LinkedModule (single letter A-Z)
|
||||
$LinkedModule = trim(strtoupper($LinkedModule));
|
||||
$this->LinkedModule = preg_match('/^[A-Z]$/', $LinkedModule) ? $LinkedModule : '';
|
||||
|
||||
$this->RandomID = $RandomID;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,18 +7,28 @@ class ParseXML {
|
|||
}
|
||||
|
||||
public function GetElement($InputString, $ElementName) {
|
||||
// Sanitize element name to prevent XML injection
|
||||
$ElementName = preg_replace('/[^a-zA-Z0-9_\-\s]/', '', $ElementName);
|
||||
|
||||
if (strpos($InputString, "<".$ElementName.">") === false) return false;
|
||||
if (strpos($InputString, "</".$ElementName.">") === false) return false;
|
||||
|
||||
$Element = substr($InputString, strpos($InputString, "<".$ElementName.">")+strlen($ElementName)+2, strpos($InputString, "</".$ElementName.">")-strpos($InputString, "<".$ElementName.">")-strlen($ElementName)-2);
|
||||
return $Element;
|
||||
|
||||
// Strip any remaining HTML/XML tags from the content
|
||||
return strip_tags($Element);
|
||||
}
|
||||
|
||||
public function GetAllElements($InputString, $ElementName) {
|
||||
// Sanitize element name to prevent XML injection
|
||||
$ElementName = preg_replace('/[^a-zA-Z0-9_\-\s]/', '', $ElementName);
|
||||
|
||||
$Elements = array();
|
||||
while (strpos($InputString, $ElementName) !== false) {
|
||||
$Elements[] = $this->GetElement($InputString, $ElementName);
|
||||
$element = $this->GetElement($InputString, $ElementName);
|
||||
if ($element !== false) {
|
||||
$Elements[] = $element;
|
||||
}
|
||||
$InputString = substr($InputString, strpos($InputString, "</".$ElementName.">")+strlen($ElementName)+3, strlen($InputString));
|
||||
}
|
||||
return $Elements;
|
||||
|
|
|
|||
|
|
@ -11,12 +11,29 @@ class Peer {
|
|||
|
||||
public function __construct($Callsign, $IP, $LinkedModule, $Protocol, $ConnectTime, $LastHeardTime) {
|
||||
|
||||
$this->IP = $IP;
|
||||
$this->Protocol = $Protocol;
|
||||
// Validate and sanitize IP
|
||||
$IP = trim($IP);
|
||||
$this->IP = filter_var($IP, FILTER_VALIDATE_IP) ? $IP : '0.0.0.0';
|
||||
|
||||
// Validate protocol
|
||||
$Protocol = trim($Protocol);
|
||||
$allowed_protocols = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS'];
|
||||
$this->Protocol = in_array($Protocol, $allowed_protocols, true) ? $Protocol : 'Unknown';
|
||||
|
||||
$this->ConnectTime = ParseTime($ConnectTime);
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
$this->Callsign = trim($Callsign);
|
||||
$this->LinkedModule = trim($LinkedModule);
|
||||
|
||||
// Sanitize and validate callsign
|
||||
$Callsign = trim($Callsign);
|
||||
if (preg_match('/^[A-Z0-9]{3,10}$/i', $Callsign)) {
|
||||
$this->Callsign = strtoupper($Callsign);
|
||||
} else {
|
||||
$this->Callsign = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate LinkedModule (single letter A-Z)
|
||||
$LinkedModule = trim(strtoupper($LinkedModule));
|
||||
$this->LinkedModule = preg_match('/^[A-Z]$/', $LinkedModule) ? $LinkedModule : '';
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ class xReflector {
|
|||
|
||||
# XLX alphanumeric naming...
|
||||
$this->ServiceName = substr($this->XMLContent, strpos($this->XMLContent, "<XLX")+4, 3);
|
||||
if (preg_match('/[^a-zA-Z0-9]/', $this->ServiceName) == 1) {
|
||||
|
||||
// Validate service name
|
||||
if (!preg_match('/^[a-zA-Z0-9]{3}$/', $this->ServiceName)) {
|
||||
$this->ServiceName = null;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -61,25 +63,46 @@ class xReflector {
|
|||
$tmpNodes = $XML->GetAllElements($AllNodesString, "NODE");
|
||||
|
||||
for ($i=0;$i<count($tmpNodes);$i++) {
|
||||
$Node = new Node($XML->GetElement($tmpNodes[$i], 'Callsign'), $XML->GetElement($tmpNodes[$i], 'IP'), $XML->GetElement($tmpNodes[$i], 'LinkedModule'), $XML->GetElement($tmpNodes[$i], 'Protocol'), $XML->GetElement($tmpNodes[$i], 'ConnectTime'), $XML->GetElement($tmpNodes[$i], 'LastHeardTime'), CreateCode(16));
|
||||
$Node = new Node(
|
||||
$XML->GetElement($tmpNodes[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpNodes[$i], 'IP'),
|
||||
$XML->GetElement($tmpNodes[$i], 'LinkedModule'),
|
||||
$XML->GetElement($tmpNodes[$i], 'Protocol'),
|
||||
$XML->GetElement($tmpNodes[$i], 'ConnectTime'),
|
||||
$XML->GetElement($tmpNodes[$i], 'LastHeardTime'),
|
||||
CreateCode(16)
|
||||
);
|
||||
$this->AddNode($Node);
|
||||
}
|
||||
|
||||
$AllStationsString = $XML->GetElement($this->XMLContent, $LinkedUsersName);
|
||||
$tmpStations = $XML->GetAllElements($AllStationsString, "STATION");
|
||||
for ($i=0;$i<count($tmpStations);$i++) {
|
||||
$Station = new Station($XML->GetElement($tmpStations[$i], 'Callsign'), $XML->GetElement($tmpStations[$i], 'Via node'), $XML->GetElement($tmpStations[$i], 'Via peer'), $XML->GetElement($tmpStations[$i], 'LastHeardTime'), $XML->GetElement($tmpStations[$i], 'On module'));
|
||||
$Station = new Station(
|
||||
$XML->GetElement($tmpStations[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpStations[$i], 'Via node'),
|
||||
$XML->GetElement($tmpStations[$i], 'Via peer'),
|
||||
$XML->GetElement($tmpStations[$i], 'LastHeardTime'),
|
||||
$XML->GetElement($tmpStations[$i], 'On module')
|
||||
);
|
||||
$this->AddStation($Station, false);
|
||||
}
|
||||
|
||||
$AllPeersString = $XML->GetElement($this->XMLContent, $LinkedPeersName);
|
||||
$tmpPeers = $XML->GetAllElements($AllPeersString, "PEER");
|
||||
for ($i=0;$i<count($tmpPeers);$i++) {
|
||||
$Peer = new Peer($XML->GetElement($tmpPeers[$i], 'Callsign'), $XML->GetElement($tmpPeers[$i], 'IP'), $XML->GetElement($tmpPeers[$i], 'LinkedModule'), $XML->GetElement($tmpPeers[$i], 'Protocol'), $XML->GetElement($tmpPeers[$i], 'ConnectTime'), $XML->GetElement($tmpPeers[$i], 'LastHeardTime'));
|
||||
$Peer = new Peer(
|
||||
$XML->GetElement($tmpPeers[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpPeers[$i], 'IP'),
|
||||
$XML->GetElement($tmpPeers[$i], 'LinkedModule'),
|
||||
$XML->GetElement($tmpPeers[$i], 'Protocol'),
|
||||
$XML->GetElement($tmpPeers[$i], 'ConnectTime'),
|
||||
$XML->GetElement($tmpPeers[$i], 'LastHeardTime')
|
||||
);
|
||||
$this->AddPeer($Peer, false);
|
||||
}
|
||||
|
||||
$this->Version = $XML->GetElement($this->XMLContent, "Version");
|
||||
$this->Version = strip_tags($XML->GetElement($this->XMLContent, "Version"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,16 +115,25 @@ class xReflector {
|
|||
}
|
||||
|
||||
public function SetXMLFile($XMLFile) {
|
||||
if (file_exists($XMLFile) && (is_readable($XMLFile))) {
|
||||
// Prevent path traversal
|
||||
$XMLFile = basename($XMLFile);
|
||||
$XMLFile = '/var/log/' . $XMLFile; // Force it to expected directory
|
||||
|
||||
if (file_exists($XMLFile) && is_readable($XMLFile)) {
|
||||
$this->XMLFile = $XMLFile;
|
||||
}
|
||||
else {
|
||||
die("File ".$XMLFile." does not exist or is not readable");
|
||||
error_log("XML File ".$XMLFile." does not exist or is not readable");
|
||||
$this->XMLFile = null;
|
||||
$this->XMLContent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetPIDFile($ProcessIDFile) {
|
||||
// Prevent path traversal
|
||||
$ProcessIDFile = basename($ProcessIDFile);
|
||||
$ProcessIDFile = '/var/log/' . $ProcessIDFile;
|
||||
|
||||
if (file_exists($ProcessIDFile)) {
|
||||
$this->ProcessIDFile = $ProcessIDFile;
|
||||
$this->ServiceUptime = time() - filectime($ProcessIDFile);
|
||||
|
|
@ -117,8 +149,14 @@ class xReflector {
|
|||
}
|
||||
|
||||
public function SetFlagFile($Flagfile) {
|
||||
if (file_exists($Flagfile) && (is_readable($Flagfile))) {
|
||||
$this->Flagfile = $Flagfile;
|
||||
// Prevent path traversal
|
||||
$realPath = realpath($Flagfile);
|
||||
if ($realPath === false || strpos($realPath, '/dashboard/pgs/') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_exists($realPath) && is_readable($realPath)) {
|
||||
$this->Flagfile = $realPath;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -346,6 +384,18 @@ class xReflector {
|
|||
if (!isset($CallingHomeVariables['OverrideIPAddress'])) { $CallingHomeVariables['OverrideIPAddress'] = false; }
|
||||
if (!isset($CallingHomeVariables['InterlinkFile'])) { $CallingHomeVariables['InterlinkFile'] = ''; }
|
||||
|
||||
// Validate URLs
|
||||
if (!empty($CallingHomeVariables['MyDashBoardURL'])) {
|
||||
if (filter_var($CallingHomeVariables['MyDashBoardURL'], FILTER_VALIDATE_URL) === false) {
|
||||
$CallingHomeVariables['MyDashBoardURL'] = '';
|
||||
}
|
||||
}
|
||||
if (!empty($CallingHomeVariables['ServerURL'])) {
|
||||
if (filter_var($CallingHomeVariables['ServerURL'], FILTER_VALIDATE_URL) === false) {
|
||||
$CallingHomeVariables['ServerURL'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($CallingHomeVariables['InterlinkFile'])) {
|
||||
$this->Interlinkfile = '';
|
||||
$this->Transferinterlink = false;
|
||||
|
|
@ -370,16 +420,31 @@ class xReflector {
|
|||
}
|
||||
|
||||
public function ReadInterlinkFile() {
|
||||
if (file_exists($this->Interlinkfile) && (is_readable($this->Interlinkfile))) {
|
||||
if (empty($this->Interlinkfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent path traversal
|
||||
$realPath = realpath($this->Interlinkfile);
|
||||
if ($realPath === false || strpos($realPath, '/xlxd/') === false) {
|
||||
error_log("ReadInterlinkFile blocked - invalid path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_exists($realPath) && is_readable($realPath)) {
|
||||
$this->Interlinks = array();
|
||||
$this->InterlinkXML = "";
|
||||
$Interlinkfilecontent = file($this->Interlinkfile);
|
||||
$Interlinkfilecontent = file($realPath);
|
||||
for ($i=0;$i<count($Interlinkfilecontent);$i++) {
|
||||
if (substr($Interlinkfilecontent[$i], 0, 1) != '#') {
|
||||
$Interlink = explode(" ", $Interlinkfilecontent[$i]);
|
||||
$this->Interlinks[] = new Interlink();
|
||||
if (isset($Interlink[0])) { $this->Interlinks[count($this->Interlinks)-1]->SetName(trim($Interlink[0])); }
|
||||
if (isset($Interlink[1])) { $this->Interlinks[count($this->Interlinks)-1]->SetAddress(trim($Interlink[1])); }
|
||||
if (isset($Interlink[0])) {
|
||||
$this->Interlinks[count($this->Interlinks)-1]->SetName(trim($Interlink[0]));
|
||||
}
|
||||
if (isset($Interlink[1])) {
|
||||
$this->Interlinks[count($this->Interlinks)-1]->SetAddress(trim($Interlink[1]));
|
||||
}
|
||||
if (isset($Interlink[2])) {
|
||||
$Modules = str_split(trim($Interlink[2]), 1);
|
||||
for ($j=0;$j<count($Modules);$j++) {
|
||||
|
|
@ -399,9 +464,9 @@ class xReflector {
|
|||
for ($i=0;$i<count($this->Interlinks);$i++) {
|
||||
$xml .= '
|
||||
<interlink>
|
||||
<name>'.$this->Interlinks[$i]->GetName().'</name>
|
||||
<address>'.$this->Interlinks[$i]->GetAddress().'</address>
|
||||
<modules>'.$this->Interlinks[$i]->GetModules().'</modules>
|
||||
<name>'.htmlspecialchars($this->Interlinks[$i]->GetName(), ENT_XML1, 'UTF-8').'</name>
|
||||
<address>'.htmlspecialchars($this->Interlinks[$i]->GetAddress(), ENT_XML1, 'UTF-8').'</address>
|
||||
<modules>'.htmlspecialchars($this->Interlinks[$i]->GetModules(), ENT_XML1, 'UTF-8').'</modules>
|
||||
</interlink>';
|
||||
}
|
||||
$xml .= '
|
||||
|
|
@ -412,27 +477,48 @@ class xReflector {
|
|||
public function PrepareReflectorXML() {
|
||||
$this->ReflectorXML = '
|
||||
<reflector>
|
||||
<name>'.$this->ReflectorName.'</name>
|
||||
<uptime>'.$this->ServiceUptime.'</uptime>
|
||||
<hash>'.$this->CallingHomeHash.'</hash>
|
||||
<url>'.$this->CallingHomeDashboardURL.'</url>
|
||||
<country>'.$this->CallingHomeCountry.'</country>
|
||||
<comment>'.$this->CallingHomeComment.'</comment>
|
||||
<ip>'.$this->CallingHomeOverrideIP.'</ip>
|
||||
<reflectorversion>'.$this->Version.'</reflectorversion>
|
||||
<name>'.htmlspecialchars($this->ReflectorName, ENT_XML1, 'UTF-8').'</name>
|
||||
<uptime>'.intval($this->ServiceUptime).'</uptime>
|
||||
<hash>'.htmlspecialchars($this->CallingHomeHash, ENT_XML1, 'UTF-8').'</hash>
|
||||
<url>'.htmlspecialchars($this->CallingHomeDashboardURL, ENT_XML1, 'UTF-8').'</url>
|
||||
<country>'.htmlspecialchars($this->CallingHomeCountry, ENT_XML1, 'UTF-8').'</country>
|
||||
<comment>'.htmlspecialchars($this->CallingHomeComment, ENT_XML1, 'UTF-8').'</comment>
|
||||
<ip>'.htmlspecialchars($this->CallingHomeOverrideIP, ENT_XML1, 'UTF-8').'</ip>
|
||||
<reflectorversion>'.htmlspecialchars($this->Version, ENT_XML1, 'UTF-8').'</reflectorversion>
|
||||
</reflector>';
|
||||
}
|
||||
|
||||
public function CallHome() {
|
||||
// Validate ServerURL is not localhost/internal IP
|
||||
$parsed = parse_url($this->CallingHomeServerURL);
|
||||
if (!isset($parsed['host'])) {
|
||||
error_log("CallHome failed - invalid URL");
|
||||
return false;
|
||||
}
|
||||
|
||||
$ip = gethostbyname($parsed['host']);
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
|
||||
error_log("CallHome blocked - internal/private IP detected");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sanitize all data being sent
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<query>CallingHome</query>'.$this->ReflectorXML.$this->InterlinkXML;
|
||||
$p = @stream_context_create(array('http' => array('header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
||||
|
||||
$p = @stream_context_create(array('http' => array(
|
||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => http_build_query(array('xml' => $xml)) )));
|
||||
'content' => http_build_query(array('xml' => $xml)),
|
||||
'timeout' => 10
|
||||
)));
|
||||
|
||||
$result = @file_get_contents($this->CallingHomeServerURL, false, $p);
|
||||
if ($result === false) {
|
||||
die("CONNECTION FAILED!");
|
||||
error_log("CallHome connection failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function InterlinkCount() {
|
||||
|
|
@ -440,14 +526,16 @@ class xReflector {
|
|||
}
|
||||
|
||||
public function GetInterlink($Index) {
|
||||
if (isset($this->Interlinks[$Index])) return $this->Interlinks[$Index];
|
||||
return array();
|
||||
if (isset($this->Interlinks[$Index])) {
|
||||
return $this->Interlinks[$Index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsInterlinked($Reflectorname) {
|
||||
$i = -1;
|
||||
$f = false;
|
||||
while (!$f && $i<$this->InterlinkCount()) {
|
||||
while (!$f && $i < $this->InterlinkCount()) {
|
||||
$i++;
|
||||
if (isset($this->Interlinks[$i])) {
|
||||
if ($this->Interlinks[$i]->GetName() == $Reflectorname) {
|
||||
|
|
@ -458,7 +546,5 @@ class xReflector {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -11,20 +11,34 @@ class Station {
|
|||
private $OnModule;
|
||||
|
||||
public function __construct($Callsign, $Via, $Peer, $LastHeardTime, $OnModule) {
|
||||
$this->Callsign = trim($Callsign);
|
||||
// Sanitize and validate callsign
|
||||
$Callsign = trim($Callsign);
|
||||
$this->Callsign = $Callsign;
|
||||
|
||||
// Sanitize Via and Peer
|
||||
$this->Via = trim($Via);
|
||||
$this->Peer = trim($Peer);
|
||||
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
|
||||
if (strpos($Callsign, " / ") !== false) {
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " / ")+3, strlen($Callsign)));
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " / ")+3));
|
||||
}
|
||||
else {
|
||||
$this->Suffix = "";
|
||||
}
|
||||
|
||||
$tmp = explode(" ", $Callsign);
|
||||
$this->CallsignOnly = $tmp[0];
|
||||
$this->OnModule = $OnModule;
|
||||
$this->CallsignOnly = isset($tmp[0]) ? trim($tmp[0]) : '';
|
||||
|
||||
// Validate callsign format
|
||||
if (!empty($this->CallsignOnly) && !preg_match('/^[A-Z0-9]{1,10}$/i', $this->CallsignOnly)) {
|
||||
$this->CallsignOnly = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate OnModule (single letter A-Z)
|
||||
$OnModule = trim(strtoupper($OnModule));
|
||||
$this->OnModule = preg_match('/^[A-Z]$/', $OnModule) ? $OnModule : '';
|
||||
}
|
||||
|
||||
public function GetCallsign() { return $this->Callsign; }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ $VNStat = array();
|
|||
|
||||
$PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address
|
||||
|
||||
$PageOptions['DashboardVersion'] = '2.4.2'; // Dashboard Version
|
||||
$PageOptions['DashboardVersion'] = '2.4.3'; // Dashboard Version
|
||||
|
||||
$PageOptions['PageRefreshActive'] = true; // Activate automatic refresh
|
||||
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
|
||||
|
|
@ -78,8 +78,13 @@ include an extra config file for people who dont like to mess with shipped confi
|
|||
this makes updating dashboard from git a little bit easier
|
||||
*/
|
||||
|
||||
if (file_exists("../config.inc.php")) {
|
||||
include ("../config.inc.php");
|
||||
$external_config = dirname(__FILE__) . '/../config.inc.php';
|
||||
if (file_exists($external_config)) {
|
||||
$realPath = realpath($external_config);
|
||||
// Only allow if it's in parent directory
|
||||
if ($realPath !== false && dirname($realPath) === dirname(dirname(__FILE__))) {
|
||||
include($realPath);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,60 @@
|
|||
<?php
|
||||
function sanitize_output($string) {
|
||||
if ($string === null) return '';
|
||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
}
|
||||
|
||||
function sanitize_attribute($string) {
|
||||
if ($string === null) return '';
|
||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
}
|
||||
|
||||
function validate_callsign($callsign) {
|
||||
$callsign = trim($callsign);
|
||||
if (preg_match('/^[A-Z0-9\-\/\s]{3,20}$/i', $callsign)) {
|
||||
return strtoupper($callsign);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function validate_module($module) {
|
||||
$module = trim(strtoupper($module));
|
||||
if (preg_match('/^[A-Z]$/', $module)) {
|
||||
return $module;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function validate_protocol($protocol) {
|
||||
$allowed = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS'];
|
||||
return in_array(trim($protocol), $allowed, true) ? trim($protocol) : '';
|
||||
}
|
||||
|
||||
function GetSystemUptime() {
|
||||
$out = exec("uptime");
|
||||
return substr($out, 0, strpos($out, ","));
|
||||
if (file_exists('/proc/uptime')) {
|
||||
$uptime = @file_get_contents('/proc/uptime');
|
||||
if ($uptime !== false) {
|
||||
$parts = explode(' ', $uptime);
|
||||
return isset($parts[0]) ? (int)$parts[0] : 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function Debug($message) {
|
||||
if (defined('DEBUG_MODE') && DEBUG_MODE === true) {
|
||||
echo '<br><hr><pre>';
|
||||
print_r($message);
|
||||
print_r($message); // Don't sanitize here as it's debug only
|
||||
echo '</pre><hr><br>';
|
||||
}
|
||||
}
|
||||
|
||||
function ParseTime($Input) {
|
||||
if (empty($Input) || !is_string($Input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$Input = strip_tags($Input); // Remove any HTML tags
|
||||
|
||||
if (strpos($Input, "<") !== false) {
|
||||
$Input = substr($Input, 0, strpos($Input, "<"));
|
||||
|
|
@ -19,12 +62,29 @@ function ParseTime($Input) {
|
|||
|
||||
// Tuesday Tue Nov 17 14:23:22 2015
|
||||
$tmp = explode(" ", $Input);
|
||||
|
||||
// Add bounds checking
|
||||
if (count($tmp) < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen(trim($tmp[3])) == 0) {
|
||||
unset($tmp[3]);
|
||||
$tmp = array_values($tmp);
|
||||
}
|
||||
|
||||
// Check array indices exist after potential unset
|
||||
if (!isset($tmp[4]) || !isset($tmp[2]) || !isset($tmp[3]) || !isset($tmp[5])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp1 = explode(":", $tmp[4]);
|
||||
|
||||
// Check time parts exist
|
||||
if (count($tmp1) < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$month = "";
|
||||
switch (strtolower($tmp[2])) {
|
||||
case 'jan' : $month = 1; break;
|
||||
|
|
@ -42,7 +102,6 @@ function ParseTime($Input) {
|
|||
default : $month = 1;
|
||||
}
|
||||
return @mktime($tmp1[0], $tmp1[1], $tmp1[2], $month, $tmp[3], $tmp[5]);
|
||||
|
||||
}
|
||||
|
||||
function FormatSeconds($seconds) {
|
||||
|
|
@ -70,9 +129,23 @@ function VNStatLocalize($str) {
|
|||
}
|
||||
|
||||
function VNStatGetData($iface, $vnstat_bin) {
|
||||
// Validate interface name (only allow alphanumeric, dash, underscore)
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $iface)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate vnstat binary path
|
||||
if (!file_exists($vnstat_bin) || !is_executable($vnstat_bin)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Escape shell arguments
|
||||
$iface_escaped = escapeshellarg($iface);
|
||||
$vnstat_bin_escaped = escapeshellarg($vnstat_bin);
|
||||
|
||||
$vnstat_data = array();
|
||||
|
||||
$fd = @popen("$vnstat_bin --dumpdb -i $iface", "r");
|
||||
$fd = @popen("$vnstat_bin_escaped --dumpdb -i $iface_escaped", "r");
|
||||
if (is_resource($fd)) {
|
||||
$buffer = '';
|
||||
while (!feof($fd)) {
|
||||
|
|
|
|||
|
|
@ -32,17 +32,17 @@ for ($i = 1; $i <= $NumberOfModules; $i++) {
|
|||
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center">'. $module .'</td>
|
||||
<td align="center">'. (empty($PageOptions['ModuleNames'][$module]) ? '-' : $PageOptions['ModuleNames'][$module]) .'</td>
|
||||
<td align="center">'. sanitize_output($module) .'</td>
|
||||
<td align="center">'. sanitize_output(empty($PageOptions['ModuleNames'][$module]) ? '-' : $PageOptions['ModuleNames'][$module]) .'</td>
|
||||
<td align="center">'. count($Reflector->GetNodesInModulesByID($module)) .'</td>
|
||||
<td align="center">'. 'REF' . $ReflectorNumber . $module . 'L' .'</td>
|
||||
<td align="center">'. (is_numeric($ReflectorNumber) ? '*' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. 'XRF' . $ReflectorNumber . $module . 'L' .'</td>
|
||||
<td align="center">'. (is_numeric($ReflectorNumber) ? 'B' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. 'DCS' . $ReflectorNumber . $module . 'L' .'</td>
|
||||
<td align="center">'. (is_numeric($ReflectorNumber) ? 'D' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. (4000+$i) .'</td>
|
||||
<td align="center">'. (9+$i) .'</td>
|
||||
<td align="center">'. sanitize_output('REF' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? '*' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output('XRF' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? 'B' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output('DCS' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? 'D' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output(4000+$i) .'</td>
|
||||
<td align="center">'. sanitize_output(9+$i) .'</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,26 +54,26 @@ for ($i=0;$i<$Reflector->PeerCount();$i++) {
|
|||
}
|
||||
if ($Result && (trim($URL) != "")) {
|
||||
echo '
|
||||
<td><a href="'.$URL.'" target="_blank" class="listinglink" title="Visit the Dashboard of '.$Name.'" style="text-decoration:none;color:#000000;">'.$Name.'</a></td>';
|
||||
<td><a href="'.sanitize_attribute($URL).'" target="_blank" class="listinglink" title="Visit the Dashboard of '.sanitize_attribute($Name).'" style="text-decoration:none;color:#000000;">'.sanitize_output($Name).'</a></td>';
|
||||
} else {
|
||||
echo '
|
||||
<td>'.$Name.'</td>';
|
||||
<td>'.sanitize_output($Name).'</td>';
|
||||
}
|
||||
echo '
|
||||
<td>'.date("d.m.Y H:i", $Reflector->Peers[$i]->GetLastHeardTime()).'</td>
|
||||
<td>'.FormatSeconds(time()-$Reflector->Peers[$i]->GetConnectTime()).' s</td>
|
||||
<td align="center">'.$Reflector->Peers[$i]->GetProtocol().'</td>
|
||||
<td align="center">'.$Reflector->Peers[$i]->GetLinkedModule().'</td>';
|
||||
<td>'.sanitize_output(date("d.m.Y H:i", $Reflector->Peers[$i]->GetLastHeardTime())).'</td>
|
||||
<td>'.sanitize_output(FormatSeconds(time()-$Reflector->Peers[$i]->GetConnectTime())).' s</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Peers[$i]->GetProtocol()).'</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Peers[$i]->GetLinkedModule()).'</td>';
|
||||
if ($PageOptions['PeerPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<td>';
|
||||
$Bytes = explode(".", $Reflector->Peers[$i]->GetIP());
|
||||
if ($Bytes !== false && count($Bytes) == 4) {
|
||||
switch ($PageOptions['PeerPage']['IPModus']) {
|
||||
case 'ShowLast1ByteOfIP' : echo $PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[3]; break;
|
||||
case 'ShowLast2ByteOfIP' : echo $PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]; break;
|
||||
case 'ShowLast3ByteOfIP' : echo $PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]; break;
|
||||
default : echo $Reflector->Peers[$i]->GetIP();
|
||||
case 'ShowLast1ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast2ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast3ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
default : echo sanitize_output($Reflector->Peers[$i]->GetIP());
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ $odd = "";
|
|||
|
||||
for ($i=0;$i<count($Reflectors);$i++) {
|
||||
|
||||
$NAME = $XML->GetElement($Reflectors[$i], "name");
|
||||
$COUNTRY = $XML->GetElement($Reflectors[$i], "country");
|
||||
$LASTCONTACT = $XML->GetElement($Reflectors[$i], "lastcontact");
|
||||
$COMMENT = $XML->GetElement($Reflectors[$i], "comment");
|
||||
$DASHBOARDURL = $XML->GetElement($Reflectors[$i], "dashboardurl");
|
||||
$NAME = sanitize_output($XML->GetElement($Reflectors[$i], "name"));
|
||||
$COUNTRY = sanitize_output($XML->GetElement($Reflectors[$i], "country"));
|
||||
$LASTCONTACT = intval($XML->GetElement($Reflectors[$i], "lastcontact"));
|
||||
$COMMENT = sanitize_output($XML->GetElement($Reflectors[$i], "comment"));
|
||||
$DASHBOARDURL = sanitize_attribute($XML->GetElement($Reflectors[$i], "dashboardurl"));
|
||||
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
<?php
|
||||
|
||||
if (!isset($_SESSION['FilterCallSign'])) {
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
// Validate filter inputs
|
||||
if (isset($_SESSION['FilterCallSign']) && $_SESSION['FilterCallSign'] !== null) {
|
||||
$_SESSION['FilterCallSign'] = preg_replace('/[^A-Z0-9\*\-\/\s]/i', '', $_SESSION['FilterCallSign']);
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['FilterProtocol'])) {
|
||||
$_SESSION['FilterProtocol'] = null;
|
||||
if (isset($_SESSION['FilterProtocol']) && $_SESSION['FilterProtocol'] !== null) {
|
||||
$_SESSION['FilterProtocol'] = validate_protocol($_SESSION['FilterProtocol']);
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['FilterModule'])) {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
if (isset($_SESSION['FilterModule']) && $_SESSION['FilterModule'] !== null) {
|
||||
$_SESSION['FilterModule'] = validate_module($_SESSION['FilterModule']);
|
||||
}
|
||||
|
||||
if (isset($_POST['do'])) {
|
||||
|
|
@ -75,7 +74,7 @@ if ($PageOptions['UserPage']['ShowFilter']) {
|
|||
<td align="left">
|
||||
<form name="frmFilterCallSign" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.$_SESSION['FilterCallSign'].'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterCallSign']).'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>';
|
||||
|
|
@ -87,14 +86,14 @@ if ($PageOptions['UserPage']['ShowFilter']) {
|
|||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterProtocol" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.$_SESSION['FilterProtocol'].'" name="txtSetProtocolFilter" placeholder="Protocol" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterProtocol']).'" name="txtSetProtocolFilter" placeholder="Protocol" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterModule" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.$_SESSION['FilterModule'].'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterModule']).'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
|
|
@ -161,13 +160,13 @@ for ($i=0;$i<$Reflector->NodeCount();$i++) {
|
|||
<td align="center">';
|
||||
list ($Flag, $Name) = $Reflector->GetFlag($Reflector->Nodes[$i]->GetCallSign());
|
||||
if (file_exists("./img/flags/".$Flag.".png")) {
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.$Flag.'.png" height="15" alt="'.$Name.'" /><span>'.$Name.'</span></a>';
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.sanitize_attribute($Flag).'.png" height="15" alt="'.sanitize_attribute($Name).'" /><span>'.sanitize_output($Name).'</span></a>';
|
||||
}
|
||||
echo '</td>
|
||||
<td><a href="http://www.aprs.fi/'.$Reflector->Nodes[$i]->GetCallSign();
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") echo '-'.$Reflector->Nodes[$i]->GetSuffix();
|
||||
echo '" class="pl" target="_blank">'.$Reflector->Nodes[$i]->GetCallSign();
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") { echo '-'.$Reflector->Nodes[$i]->GetSuffix(); }
|
||||
<td><a href="http://www.aprs.fi/'.sanitize_attribute($Reflector->Nodes[$i]->GetCallSign());
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") echo '-'.sanitize_attribute($Reflector->Nodes[$i]->GetSuffix());
|
||||
echo '" class="pl" target="_blank">'.sanitize_output($Reflector->Nodes[$i]->GetCallSign());
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") { echo '-'.sanitize_output($Reflector->Nodes[$i]->GetSuffix()); }
|
||||
echo '</a></td>
|
||||
<td>';
|
||||
if (($Reflector->Nodes[$i]->GetPrefix() == 'REF') || ($Reflector->Nodes[$i]->GetPrefix() == 'XRF')) {
|
||||
|
|
@ -187,20 +186,20 @@ for ($i=0;$i<$Reflector->NodeCount();$i++) {
|
|||
}
|
||||
}
|
||||
echo '</td>
|
||||
<td>'.date("d.m.Y H:i", $Reflector->Nodes[$i]->GetLastHeardTime()).'</td>
|
||||
<td>'.FormatSeconds(time()-$Reflector->Nodes[$i]->GetConnectTime()).' s</td>
|
||||
<td>'.$Reflector->Nodes[$i]->GetProtocol().'</td>
|
||||
<td align="center">'.$Reflector->Nodes[$i]->GetLinkedModule().'</td>';
|
||||
<td>'.sanitize_output(date("d.m.Y H:i", $Reflector->Nodes[$i]->GetLastHeardTime())).'</td>
|
||||
<td>'.sanitize_output(FormatSeconds(time()-$Reflector->Nodes[$i]->GetConnectTime())).' s</td>
|
||||
<td>'.sanitize_output($Reflector->Nodes[$i]->GetProtocol()).'</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Nodes[$i]->GetLinkedModule()).'</td>';
|
||||
if ($PageOptions['RepeatersPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<td>';
|
||||
$Bytes = explode(".", $Reflector->Nodes[$i]->GetIP());
|
||||
if ($Bytes !== false && count($Bytes) == 4) {
|
||||
switch ($PageOptions['RepeatersPage']['IPModus']) {
|
||||
case 'ShowLast1ByteOfIP' : echo $PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[3]; break;
|
||||
case 'ShowLast2ByteOfIP' : echo $PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]; break;
|
||||
case 'ShowLast3ByteOfIP' : echo $PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]; break;
|
||||
default : echo $Reflector->Nodes[$i]->GetIP();
|
||||
case 'ShowLast1ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast2ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast3ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
default : echo sanitize_output($Reflector->Nodes[$i]->GetIP());
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
|
|
|
|||
|
|
@ -8,16 +8,17 @@ if (!isset($_GET['iface'])) {
|
|||
$_GET['iface'] = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$f = false;
|
||||
$i = 0;
|
||||
while ($i < count($VNStat['Interfaces']) && (!$f)) {
|
||||
if ($_GET['iface'] == $VNStat['Interfaces'][$i]['Address']) {
|
||||
$f = true;
|
||||
|
||||
// Validate interface name against whitelist
|
||||
if (!empty($_GET['iface'])) {
|
||||
$valid = false;
|
||||
for ($i = 0; $i < count($VNStat['Interfaces']); $i++) {
|
||||
if ($_GET['iface'] === $VNStat['Interfaces'][$i]['Address']) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (!$f) {
|
||||
if (!$valid) {
|
||||
$_GET['iface'] = "";
|
||||
}
|
||||
}
|
||||
|
|
@ -33,8 +34,8 @@ else {
|
|||
<td bgcolor="#F1FAFA" align="left" valign="top" style="padding-left:5px;"><?php
|
||||
|
||||
for ($i=0;$i<count($VNStat['Interfaces']);$i++) {
|
||||
echo '<a href="./index.php?show=traffic&iface='.$VNStat['Interfaces'][$i]['Address'].'" class="listinglink">'.$VNStat['Interfaces'][$i]['Name'].'</a>';
|
||||
if ($i < count($VNStat['Interfaces'])) {
|
||||
echo '<a href="./index.php?show=traffic&iface='.sanitize_attribute($VNStat['Interfaces'][$i]['Address']).'" class="listinglink">'.sanitize_output($VNStat['Interfaces'][$i]['Name']).'</a>';
|
||||
if ($i < count($VNStat['Interfaces'])-1) {
|
||||
echo '<br />';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,13 @@ if (isset($_GET['do'])) {
|
|||
}
|
||||
}
|
||||
|
||||
// Validate filter inputs
|
||||
if (isset($_SESSION['FilterCallSign']) && $_SESSION['FilterCallSign'] !== null) {
|
||||
$_SESSION['FilterCallSign'] = preg_replace('/[^A-Z0-9\*\-\/\s]/i', '', $_SESSION['FilterCallSign']);
|
||||
}
|
||||
if (isset($_SESSION['FilterModule']) && $_SESSION['FilterModule'] !== null) {
|
||||
$_SESSION['FilterModule'] = validate_module($_SESSION['FilterModule']);
|
||||
}
|
||||
|
||||
?>
|
||||
<table border="0">
|
||||
|
|
@ -63,7 +70,7 @@ if ($PageOptions['UserPage']['ShowFilter']) {
|
|||
<td align="left">
|
||||
<form name="frmFilterCallSign" method="post" action="./index.php">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.$_SESSION['FilterCallSign'].'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterCallSign']).'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>';
|
||||
|
|
@ -75,7 +82,7 @@ if ($PageOptions['UserPage']['ShowFilter']) {
|
|||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterModule" method="post" action="./index.php">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.$_SESSION['FilterModule'].'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterModule']).'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
|
|
@ -131,25 +138,24 @@ for ($i=0;$i<$Reflector->StationCount();$i++) {
|
|||
echo ($i+1);
|
||||
}
|
||||
|
||||
|
||||
echo '</td>
|
||||
<td align="center" width="60">';
|
||||
|
||||
list ($Flag, $Name) = $Reflector->GetFlag($Reflector->Stations[$i]->GetCallSign());
|
||||
if (file_exists("./img/flags/".$Flag.".png")) {
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.$Flag.'.png" height="15" alt="'.$Name.'" /><span>'.$Name.'</span></a>';
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.sanitize_attribute($Flag).'.png" height="15" alt="'.sanitize_attribute($Name).'" /><span>'.sanitize_output($Name).'</span></a>';
|
||||
}
|
||||
echo '</td>
|
||||
<td width="75"><a href="https://www.qrz.com/db/'.$Reflector->Stations[$i]->GetCallsignOnly().'" class="pl" target="_blank">'.$Reflector->Stations[$i]->GetCallsignOnly().'</a></td>
|
||||
<td width="60">'.$Reflector->Stations[$i]->GetSuffix().'</td>
|
||||
<td width="50" align="center"><a href="http://www.aprs.fi/'.$Reflector->Stations[$i]->GetCallsignOnly().'" class="pl" target="_blank"><img src="./img/sat.png" /></a></td>
|
||||
<td width="150">'.$Reflector->Stations[$i]->GetVia();
|
||||
<td width="75"><a href="https://www.qrz.com/db/'.sanitize_attribute($Reflector->Stations[$i]->GetCallsignOnly()).'" class="pl" target="_blank">'.sanitize_output($Reflector->Stations[$i]->GetCallsignOnly()).'</a></td>
|
||||
<td width="60">'.sanitize_output($Reflector->Stations[$i]->GetSuffix()).'</td>
|
||||
<td width="50" align="center"><a href="http://www.aprs.fi/'.sanitize_attribute($Reflector->Stations[$i]->GetCallsignOnly()).'" class="pl" target="_blank"><img src="./img/sat.png" /></a></td>
|
||||
<td width="150">'.sanitize_output($Reflector->Stations[$i]->GetVia());
|
||||
if ($Reflector->Stations[$i]->GetPeer() != $Reflector->GetReflectorName()) {
|
||||
echo ' / '.$Reflector->Stations[$i]->GetPeer();
|
||||
echo ' / '.sanitize_output($Reflector->Stations[$i]->GetPeer());
|
||||
}
|
||||
echo '</td>
|
||||
<td width="150">'.@date("d.m.Y H:i", $Reflector->Stations[$i]->GetLastHeardTime()).'</td>
|
||||
<td align="center" width="30">'.$Reflector->Stations[$i]->GetModule().'</td>
|
||||
<td width="150">'.sanitize_output(@date("d.m.Y H:i", $Reflector->Stations[$i]->GetLastHeardTime())).'</td>
|
||||
<td align="center" width="30">'.sanitize_output($Reflector->Stations[$i]->GetModule()).'</td>
|
||||
</tr>';
|
||||
}
|
||||
if ($i == $PageOptions['LastHeardPage']['LimitTo']) { $i = $Reflector->StationCount()+1; }
|
||||
|
|
@ -177,18 +183,15 @@ for ($i=0;$i<count($Modules);$i++) {
|
|||
|
||||
if (isset($PageOptions['ModuleNames'][$Modules[$i]])) {
|
||||
echo '
|
||||
|
||||
<th>'.$PageOptions['ModuleNames'][$Modules[$i]];
|
||||
<th>'.sanitize_output($PageOptions['ModuleNames'][$Modules[$i]]);
|
||||
if (trim($PageOptions['ModuleNames'][$Modules[$i]]) != "") {
|
||||
echo '<br />';
|
||||
}
|
||||
echo $Modules[$i].'</th>
|
||||
';
|
||||
echo sanitize_output($Modules[$i]).'</th>';
|
||||
}
|
||||
else {
|
||||
echo '
|
||||
|
||||
<th>'.$Modules[$i].'</th>';
|
||||
<th>'.sanitize_output($Modules[$i]).'</th>';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +218,7 @@ for ($i=0;$i<count($Modules);$i++) {
|
|||
$Displayname = $Reflector->GetCallsignAndSuffixByID($Users[$j]);
|
||||
echo '
|
||||
<tr height="25" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td valign="top" style="border-bottom:1px #C1DAD7 solid;"><a href="http://www.aprs.fi/'.$Displayname.'" class="pl" target="_blank">'.$Displayname.'</a> </td>
|
||||
<td valign="top" style="border-bottom:1px #C1DAD7 solid;"><a href="http://www.aprs.fi/'.sanitize_attribute($Displayname).'" class="pl" target="_blank">'.sanitize_output($Displayname).'</a> </td>
|
||||
</tr>';
|
||||
$UserCheckedArray[] = $Users[$j];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue