2016-07-05 18:29:40 +02:00
|
|
|
<?php
|
2025-11-24 11:20:31 +01:00
|
|
|
// Check if we are serving HTTPS
|
|
|
|
|
function isHttps() {
|
|
|
|
|
// Check standard HTTPS indicators
|
|
|
|
|
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Check for proxy/load balancer headers
|
|
|
|
|
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-14 13:25:26 +02:00
|
|
|
session_start();
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2025-11-24 11:20:31 +01:00
|
|
|
// Security headers
|
|
|
|
|
$isHttps = isHttps();
|
|
|
|
|
header("X-Frame-Options: SAMEORIGIN");
|
|
|
|
|
header("X-Content-Type-Options: nosniff");
|
|
|
|
|
header("X-XSS-Protection: 1; mode=block");
|
|
|
|
|
header("Referrer-Policy: strict-origin-when-cross-origin");
|
|
|
|
|
header("Permissions-Policy: geolocation=(), microphone=(), camera=()");
|
|
|
|
|
|
|
|
|
|
// Build CSP based on protocol
|
|
|
|
|
// Allow external images via both http: and https: since we can't control external links
|
|
|
|
|
$imgSrc = $isHttps ? "'self' data: https:" : "'self' data: http: https:";
|
|
|
|
|
|
|
|
|
|
$csp = "default-src 'self'; " .
|
|
|
|
|
"script-src 'self' 'unsafe-inline'; " .
|
|
|
|
|
"style-src 'self' 'unsafe-inline'; " .
|
|
|
|
|
"img-src {$imgSrc}; " .
|
|
|
|
|
"connect-src 'self'; " .
|
|
|
|
|
"frame-ancestors 'self'";
|
|
|
|
|
|
|
|
|
|
header("Content-Security-Policy: " . $csp);
|
|
|
|
|
|
|
|
|
|
// Only add HSTS if served over HTTPS
|
|
|
|
|
if ($isHttps) {
|
|
|
|
|
// HSTS: Force HTTPS for 1 year, but don't include subdomains (might be on local network)
|
|
|
|
|
header("Strict-Transport-Security: max-age=31536000");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-05 18:29:40 +02:00
|
|
|
/*
|
|
|
|
|
* This dashboard is being developed by the DVBrazil Team as a courtesy to
|
|
|
|
|
* the XLX Multiprotocol Gateway Reflector Server project.
|
|
|
|
|
* The dashboard is based of the Bootstrap dashboard template.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
if (file_exists("./pgs/functions.php")) {
|
|
|
|
|
require_once("./pgs/functions.php");
|
|
|
|
|
} else {
|
2025-10-14 13:25:26 +02:00
|
|
|
die("Required file not found.");
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
|
|
|
|
if (file_exists("./pgs/config.inc.php")) {
|
|
|
|
|
require_once("./pgs/config.inc.php");
|
|
|
|
|
} else {
|
2025-10-14 13:25:26 +02:00
|
|
|
die("Required file not found.");
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
if (!class_exists('ParseXML')) require_once("./pgs/class.parsexml.php");
|
|
|
|
|
if (!class_exists('Node')) require_once("./pgs/class.node.php");
|
2016-07-05 18:29:40 +02:00
|
|
|
if (!class_exists('xReflector')) require_once("./pgs/class.reflector.php");
|
2017-08-27 23:09:08 +02:00
|
|
|
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");
|
2016-07-05 18:29:40 +02:00
|
|
|
|
|
|
|
|
$Reflector = new xReflector();
|
|
|
|
|
$Reflector->SetFlagFile("./pgs/country.csv");
|
|
|
|
|
$Reflector->SetPIDFile($Service['PIDFile']);
|
|
|
|
|
$Reflector->SetXMLFile($Service['XMLFile']);
|
|
|
|
|
|
|
|
|
|
$Reflector->LoadXML();
|
|
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
if ($CallingHome['Active']) {
|
|
|
|
|
|
|
|
|
|
$CallHomeNow = false;
|
|
|
|
|
if (!file_exists($CallingHome['HashFile'])) {
|
|
|
|
|
$Hash = CreateCode(16);
|
|
|
|
|
$LastSync = 0;
|
|
|
|
|
$Ressource = @fopen($CallingHome['HashFile'], "w");
|
|
|
|
|
if ($Ressource) {
|
2016-07-05 18:29:40 +02:00
|
|
|
@fwrite($Ressource, "<?php\n");
|
2017-08-27 23:09:08 +02:00
|
|
|
@fwrite($Ressource, "\n" . '$LastSync = 0;');
|
|
|
|
|
@fwrite($Ressource, "\n" . '$Hash = "' . $Hash . '";');
|
|
|
|
|
@fwrite($Ressource, "\n\n" . '?>');
|
2016-07-05 18:29:40 +02:00
|
|
|
@fclose($Ressource);
|
2025-10-14 13:25:26 +02:00
|
|
|
@exec("chmod 600 " . $CallingHome['HashFile']);
|
2017-08-27 23:09:08 +02:00
|
|
|
$CallHomeNow = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
include($CallingHome['HashFile']);
|
|
|
|
|
if ($LastSync < (time() - $CallingHome['PushDelay'])) {
|
|
|
|
|
$Ressource = @fopen($CallingHome['HashFile'], "w");
|
|
|
|
|
if ($Ressource) {
|
|
|
|
|
@fwrite($Ressource, "<?php\n");
|
|
|
|
|
@fwrite($Ressource, "\n" . '$LastSync = ' . time() . ';');
|
|
|
|
|
@fwrite($Ressource, "\n" . '$Hash = "' . $Hash . '";');
|
|
|
|
|
@fwrite($Ressource, "\n\n" . '?>');
|
|
|
|
|
@fclose($Ressource);
|
|
|
|
|
}
|
|
|
|
|
$CallHomeNow = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($CallHomeNow || isset($_GET['callhome'])) {
|
|
|
|
|
$Reflector->SetCallingHome($CallingHome, $Hash);
|
|
|
|
|
$Reflector->ReadInterlinkFile();
|
|
|
|
|
$Reflector->PrepareInterlinkXML();
|
|
|
|
|
$Reflector->PrepareReflectorXML();
|
|
|
|
|
$Reflector->CallHome();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$Hash = "";
|
2016-07-05 18:29:40 +02:00
|
|
|
}
|
|
|
|
|
?>
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
2017-08-27 23:09:08 +02:00
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
2025-10-14 13:25:26 +02:00
|
|
|
<meta name="description" content="<?php echo SafeOutputAttr($PageOptions['MetaDescription']); ?>"/>
|
|
|
|
|
<meta name="keywords" content="<?php echo SafeOutputAttr($PageOptions['MetaKeywords']); ?>"/>
|
|
|
|
|
<meta name="author" content="<?php echo SafeOutputAttr($PageOptions['MetaAuthor']); ?>"/>
|
|
|
|
|
<meta name="revisit" content="<?php echo SafeOutputAttr($PageOptions['MetaRevisit']); ?>"/>
|
|
|
|
|
<meta name="robots" content="<?php echo SafeOutputAttr($PageOptions['MetaAuthor']); ?>"/>
|
2017-08-27 23:09:08 +02:00
|
|
|
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
|
|
|
|
|
<title><?php echo $Reflector->GetReflectorName(); ?> Reflector Dashboard</title>
|
|
|
|
|
<link rel="icon" href="./favicon.ico" type="image/vnd.microsoft.icon">
|
|
|
|
|
<!-- Bootstrap core CSS -->
|
|
|
|
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
|
|
|
|
|
|
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
|
|
|
|
<link href="css/ie10-viewport-bug-workaround.css" rel="stylesheet">
|
|
|
|
|
|
|
|
|
|
<!-- Custom styles for this template -->
|
|
|
|
|
<link href="css/dashboard.css" rel="stylesheet">
|
|
|
|
|
|
|
|
|
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
|
|
|
|
<!--[if lt IE 9]>
|
|
|
|
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
|
|
|
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
|
|
|
<![endif]-->
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
if ($PageOptions['PageRefreshActive']) {
|
|
|
|
|
echo '
|
2016-07-05 18:29:40 +02:00
|
|
|
<script>
|
2018-02-03 02:53:37 +01:00
|
|
|
var PageRefresh;
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2018-02-03 02:32:25 +01:00
|
|
|
function ReloadPage() {';
|
2018-02-06 09:12:24 +01:00
|
|
|
if (($_SERVER['REQUEST_METHOD'] === 'POST') || isset($_GET['do'])) {
|
2018-02-03 02:32:25 +01:00
|
|
|
echo '
|
2016-07-05 18:29:40 +02:00
|
|
|
document.location.href = "./index.php';
|
2025-10-14 13:25:26 +02:00
|
|
|
if (isset($_GET['show']) && $_GET['show'] !== '') {
|
|
|
|
|
echo '?show=' . SafeOutput($_GET['show']);
|
2018-02-03 02:32:25 +01:00
|
|
|
}
|
|
|
|
|
echo '";';
|
|
|
|
|
} else {
|
|
|
|
|
echo '
|
|
|
|
|
document.location.reload();';
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
2018-02-03 02:32:25 +01:00
|
|
|
echo '
|
2016-07-05 18:29:40 +02:00
|
|
|
}';
|
|
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) {
|
|
|
|
|
echo '
|
2018-02-03 02:53:37 +01:00
|
|
|
PageRefresh = setTimeout(ReloadPage, ' . $PageOptions['PageRefreshDelay'] . ');';
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
|
|
|
|
echo '
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2018-02-03 02:53:37 +01:00
|
|
|
function SuspendPageRefresh() {
|
|
|
|
|
clearTimeout(PageRefresh);
|
|
|
|
|
}
|
2016-07-05 18:29:40 +02:00
|
|
|
</script>';
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
|
|
|
|
if (!isset($_GET['show'])) $_GET['show'] = "";
|
|
|
|
|
?>
|
2016-07-05 18:29:40 +02:00
|
|
|
</head>
|
|
|
|
|
<body>
|
2017-08-27 23:09:08 +02:00
|
|
|
<?php if (file_exists("./tracking.php")) {
|
|
|
|
|
include_once("tracking.php");
|
|
|
|
|
} ?>
|
|
|
|
|
<nav class="navbar navbar-inverse navbar-fixed-top">
|
|
|
|
|
<div class="container-fluid">
|
2016-07-05 18:29:40 +02:00
|
|
|
<div class="navbar-header">
|
2017-08-27 23:09:08 +02:00
|
|
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
|
|
|
|
|
aria-expanded="false" aria-controls="navbar">
|
|
|
|
|
<span class="sr-only">Toggle navigation</span>
|
|
|
|
|
<span class="icon-bar"></span>
|
|
|
|
|
<span class="icon-bar"></span>
|
|
|
|
|
<span class="icon-bar"></span>
|
|
|
|
|
</button>
|
|
|
|
|
<span class="navbar-brand"><?php echo $Reflector->GetReflectorName(); ?> Multiprotocol Gateway</span>
|
2016-07-05 18:29:40 +02:00
|
|
|
</div>
|
|
|
|
|
<div id="navbar" class="navbar-collapse collapse">
|
2017-08-27 23:09:08 +02:00
|
|
|
<ul class="nav navbar-nav navbar-right">
|
|
|
|
|
<li class="navbar-info"><?php echo $Reflector->GetVersion(); ?> - Dashboard
|
|
|
|
|
v<?php echo $PageOptions['DashboardVersion']; ?></li>
|
|
|
|
|
<li class="navbar-info">Service
|
|
|
|
|
uptime: <?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></li>
|
|
|
|
|
</ul>
|
2016-07-05 18:29:40 +02:00
|
|
|
</div>
|
2017-08-27 23:09:08 +02:00
|
|
|
</div>
|
|
|
|
|
</nav>
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
<div class="container-fluid">
|
|
|
|
|
<div class="row">
|
2016-07-05 18:29:40 +02:00
|
|
|
<div class="col-sm-3 col-md-2 sidebar">
|
2017-08-27 23:09:08 +02:00
|
|
|
<ul class="nav nav-sidebar">
|
|
|
|
|
<li<?php echo (($_GET['show'] == "users") || ($_GET['show'] == "")) ? ' class="active"' : ''; ?>><a
|
|
|
|
|
href="./index.php">Users / Modules</a></li>
|
|
|
|
|
<li<?php echo ($_GET['show'] == "repeaters") ? ' class="active"' : ''; ?>><a
|
|
|
|
|
href="./index.php?show=repeaters">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>
|
|
|
|
|
)</a></li>
|
|
|
|
|
<li<?php echo ($_GET['show'] == "peers") ? ' class="active"' : ''; ?>><a href="./index.php?show=peers">Peers
|
|
|
|
|
(<?php echo $Reflector->PeerCount(); ?>)</a></li>
|
|
|
|
|
<li<?php echo ($_GET['show'] == "reflectors") ? ' class="active"' : ''; ?>><a
|
|
|
|
|
href="./index.php?show=reflectors">Reflectorlist</a></li>
|
|
|
|
|
<li<?php echo ($_GET['show'] == "liveircddb") ? ' class="active"' : ''; ?>><a
|
|
|
|
|
href="./index.php?show=liveircddb">D-Star live</a></li>
|
|
|
|
|
</ul>
|
2016-07-05 18:29:40 +02:00
|
|
|
</div>
|
|
|
|
|
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
|
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
<?php
|
|
|
|
|
if ($CallingHome['Active']) {
|
|
|
|
|
if (!is_readable($CallingHome['HashFile']) && (!is_writeable($CallingHome['HashFile']))) {
|
|
|
|
|
echo '
|
2016-07-05 18:29:40 +02:00
|
|
|
<div class="error">
|
2017-08-27 23:09:08 +02:00
|
|
|
your private hash in ' . $CallingHome['HashFile'] . ' could not be created, please check your config file and the permissions for the defined folder.
|
2016-07-05 18:29:40 +02:00
|
|
|
</div>';
|
2017-08-27 23:09:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-14 13:25:26 +02:00
|
|
|
// Whitelist allowed values
|
|
|
|
|
if (!isset($_GET['show'])) {
|
|
|
|
|
$_GET['show'] = '';
|
|
|
|
|
}
|
|
|
|
|
$allowed_shows = ['users', 'repeaters', 'liveircddb', 'peers', 'reflectors', ''];
|
|
|
|
|
if (!in_array($_GET['show'], $allowed_shows, true)) {
|
|
|
|
|
$_GET['show'] = '';
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
switch ($_GET['show']) {
|
|
|
|
|
case 'users' :
|
|
|
|
|
require_once("./pgs/users.php");
|
|
|
|
|
break;
|
|
|
|
|
case 'repeaters' :
|
|
|
|
|
require_once("./pgs/repeaters.php");
|
|
|
|
|
break;
|
|
|
|
|
case 'liveircddb' :
|
|
|
|
|
require_once("./pgs/liveircddb.php");
|
|
|
|
|
break;
|
|
|
|
|
case 'peers' :
|
|
|
|
|
require_once("./pgs/peers.php");
|
|
|
|
|
break;
|
|
|
|
|
case 'reflectors' :
|
|
|
|
|
require_once("./pgs/reflectors.php");
|
|
|
|
|
break;
|
|
|
|
|
default :
|
|
|
|
|
require_once("./pgs/users.php");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?>
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
</div>
|
2016-07-05 18:29:40 +02:00
|
|
|
</div>
|
2017-08-27 23:09:08 +02:00
|
|
|
</div>
|
2016-07-05 18:29:40 +02:00
|
|
|
|
2017-08-27 23:09:08 +02:00
|
|
|
<footer class="footer">
|
|
|
|
|
<div class="container">
|
2025-10-14 13:25:26 +02:00
|
|
|
<p><a href="mailto:<?php echo SafeOutputAttr($PageOptions['ContactEmail']); ?>"><?php echo SafeOutput($PageOptions['ContactEmail']); ?></a>
|
2017-08-27 23:09:08 +02:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</footer>
|
|
|
|
|
|
|
|
|
|
<!-- Bootstrap core JavaScript
|
|
|
|
|
================================================== -->
|
|
|
|
|
<!-- Placed at the end of the document so the pages load faster -->
|
|
|
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
|
|
|
|
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
|
|
|
|
|
<script src="js/bootstrap.min.js"></script>
|
|
|
|
|
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
|
|
|
|
<script src="js/ie10-viewport-bug-workaround.js"></script>
|
2016-07-05 18:29:40 +02:00
|
|
|
</body>
|
|
|
|
|
</html>
|