mirror of
https://github.com/LX3JL/xlxd.git
synced 2025-12-05 23:32:00 +01:00
Merge pull request #263 from MW0MWZ/master
Adding local proxy for ircddb live data page(s) for Dashboard 1 and Dashboard 2
This commit is contained in:
commit
bf5d0148db
|
|
@ -1,3 +1,16 @@
|
|||
xlx db v2.4.5
|
||||
Fix liveircddb page broken by CSP security headers
|
||||
|
||||
- "pgs/ircddb_proxy.php" (NEW)
|
||||
* Added transparent proxy for live.ircddb.net to resolve CSP and mixed-content issues
|
||||
* Proxies all requests through local server, rewriting URLs to maintain functionality
|
||||
* Supports both HTTP and HTTPS dashboard deployments
|
||||
* Defaults to live.ircddb.net:8080, configurable via $PageOptions['IRCDDB']['URL']
|
||||
* Default page ircddblive5.html, configurable via $PageOptions['IRCDDB']['Page']
|
||||
|
||||
- "pgs/liveircddb.php"
|
||||
* Changed iframe source from direct external URL to local proxy
|
||||
|
||||
xlx db v2.4.4
|
||||
SECURITY UPDATE - Minor upgrade to further improve dashboard security
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ $VNStat = array();
|
|||
|
||||
$PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address
|
||||
|
||||
$PageOptions['DashboardVersion'] = '2.4.4'; // Dashboard Version
|
||||
$PageOptions['DashboardVersion'] = '2.4.5'; // Dashboard Version
|
||||
|
||||
$PageOptions['PageRefreshActive'] = true; // Activate automatic refresh
|
||||
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
|
||||
|
|
@ -50,7 +50,9 @@ $PageOptions['MetaRobots'] = 'index,follow'; //
|
|||
|
||||
$PageOptions['UserPage']['ShowFilter'] = true; // Show Filter on Users page
|
||||
$PageOptions['Traffic']['Show'] = false; // Enable vnstat traffic statistics
|
||||
$PageOptions['IRCDDB']['Show'] = true; // Show liveircddb, set it to false if you are running your db in https
|
||||
$PageOptions['IRCDDB']['Show'] = true; // Show liveircddb menu option
|
||||
// $PageOptions['IRCDDB']['URL'] = 'http://live.ircddb.net:8080'; // Optional: Override ircddb server URL
|
||||
// $PageOptions['IRCDDB']['Page'] = 'ircddblive5.html'; // Optional: Override ircddb page
|
||||
|
||||
$PageOptions['CustomTXT'] = ''; // custom text in your header
|
||||
|
||||
|
|
|
|||
186
dashboard1/pgs/ircddb_proxy.php
Normal file
186
dashboard1/pgs/ircddb_proxy.php
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
/**
|
||||
* Transparent proxy for live.ircddb.net
|
||||
*
|
||||
* This proxy allows the ircddb live page to be embedded in the dashboard
|
||||
* without CSP or mixed-content issues. It fetches content from the upstream
|
||||
* server and rewrites URLs to route back through this proxy.
|
||||
*/
|
||||
|
||||
// Load config to get any overrides
|
||||
if (file_exists(__DIR__ . "/config.inc.php")) {
|
||||
require_once(__DIR__ . "/config.inc.php");
|
||||
}
|
||||
if (file_exists(__DIR__ . "/../config.inc.php")) {
|
||||
require_once(__DIR__ . "/../config.inc.php");
|
||||
}
|
||||
|
||||
// Defaults - can be overridden in config.inc.php
|
||||
$ircddbBaseUrl = $PageOptions['IRCDDB']['URL'] ?? 'http://live.ircddb.net:8080';
|
||||
$ircddbDefaultPage = $PageOptions['IRCDDB']['Page'] ?? 'ircddblive5.html';
|
||||
|
||||
// Security: Remove trailing slash from base URL
|
||||
$ircddbBaseUrl = rtrim($ircddbBaseUrl, '/');
|
||||
|
||||
// Get requested path, default to the main page
|
||||
$path = $_GET['path'] ?? $ircddbDefaultPage;
|
||||
|
||||
// Security: Sanitize path - only allow alphanumeric, dots, hyphens, underscores
|
||||
// This prevents directory traversal and other path-based attacks
|
||||
if (!preg_match('/^[a-zA-Z0-9._-]+$/', $path)) {
|
||||
http_response_code(400);
|
||||
die('Invalid path');
|
||||
}
|
||||
|
||||
// Security: Block potentially dangerous file extensions
|
||||
$blockedExtensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar'];
|
||||
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||||
if (in_array($extension, $blockedExtensions)) {
|
||||
http_response_code(403);
|
||||
die('Forbidden');
|
||||
}
|
||||
|
||||
// Build the upstream URL
|
||||
$upstreamUrl = $ircddbBaseUrl . '/' . $path;
|
||||
|
||||
// Forward query parameters (except 'path')
|
||||
$queryParams = $_GET;
|
||||
unset($queryParams['path']);
|
||||
if (!empty($queryParams)) {
|
||||
$upstreamUrl .= '?' . http_build_query($queryParams);
|
||||
}
|
||||
|
||||
// Fetch content - try cURL first, fall back to file_get_contents
|
||||
$body = false;
|
||||
$contentType = 'text/html';
|
||||
$httpCode = 200;
|
||||
$error = '';
|
||||
|
||||
if (function_exists('curl_init')) {
|
||||
// Use cURL if available
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $upstreamUrl,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_MAXREDIRS => 3,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_USERAGENT => 'XLX-Dashboard-Proxy/1.0',
|
||||
CURLOPT_HEADER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$error = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($response !== false && $httpCode > 0) {
|
||||
// Split headers and body
|
||||
$headers = substr($response, 0, $headerSize);
|
||||
$body = substr($response, $headerSize);
|
||||
|
||||
// Parse Content-Type from headers
|
||||
$headerLines = explode("\r\n", $headers);
|
||||
foreach ($headerLines as $header) {
|
||||
if (stripos($header, 'Content-Type:') === 0) {
|
||||
$contentType = trim(substr($header, 13));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to file_get_contents with stream context
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => "User-Agent: XLX-Dashboard-Proxy/1.0\r\n",
|
||||
'timeout' => 15,
|
||||
'follow_location' => true,
|
||||
'max_redirects' => 3,
|
||||
]
|
||||
]);
|
||||
|
||||
$body = @file_get_contents($upstreamUrl, false, $context);
|
||||
|
||||
if ($body !== false && isset($http_response_header)) {
|
||||
// Parse response headers
|
||||
foreach ($http_response_header as $header) {
|
||||
// Get HTTP status code
|
||||
if (preg_match('/^HTTP\/\d+\.\d+\s+(\d+)/', $header, $matches)) {
|
||||
$httpCode = (int)$matches[1];
|
||||
}
|
||||
// Get Content-Type
|
||||
if (stripos($header, 'Content-Type:') === 0) {
|
||||
$contentType = trim(substr($header, 13));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error = 'Failed to fetch upstream content';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if ($body === false) {
|
||||
http_response_code(502);
|
||||
die('Upstream server unavailable: ' . htmlspecialchars($error));
|
||||
}
|
||||
|
||||
// Forward the HTTP status code
|
||||
http_response_code($httpCode);
|
||||
|
||||
// Set content type
|
||||
header('Content-Type: ' . $contentType);
|
||||
|
||||
// Determine if we need to rewrite URLs in this content
|
||||
$rewriteContent = (
|
||||
stripos($contentType, 'text/html') !== false ||
|
||||
stripos($contentType, 'text/javascript') !== false ||
|
||||
stripos($contentType, 'application/javascript') !== false ||
|
||||
stripos($contentType, 'application/x-javascript') !== false
|
||||
);
|
||||
|
||||
if ($rewriteContent && !empty($body)) {
|
||||
// Rewrite relative URLs to go through this proxy
|
||||
// Handle src="file.js", href="file.css", url("file"), etc.
|
||||
|
||||
// Rewrite src attributes
|
||||
$body = preg_replace(
|
||||
'/src\s*=\s*"([^"\/][^"]*)"/',
|
||||
'src="ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
$body = preg_replace(
|
||||
"/src\s*=\s*'([^'\/][^']*)'/",
|
||||
"src='ircddb_proxy.php?path=\$1'",
|
||||
$body
|
||||
);
|
||||
|
||||
// Rewrite href attributes (for CSS, etc.)
|
||||
$body = preg_replace(
|
||||
'/href\s*=\s*"([^"\/][^"]*\.(css|ico))"/',
|
||||
'href="ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
$body = preg_replace(
|
||||
"/href\s*=\s*'([^'\/][^']*\.(css|ico))'/",
|
||||
"href='ircddb_proxy.php?path=\$1'",
|
||||
$body
|
||||
);
|
||||
|
||||
// Rewrite AJAX calls in JavaScript (the jj.yaws or jj3.yaws polling)
|
||||
// The original livelog.js uses: url: "jj.yaws", data: "p=" + lastNum
|
||||
// jQuery appends data as query string, so we need: url: "ircddb_proxy.php?path=jj.yaws"
|
||||
// Then jQuery will make it: ircddb_proxy.php?path=jj.yaws&p=123
|
||||
$body = preg_replace(
|
||||
'/url:\s*"(jj[0-9]*\.yaws)"/',
|
||||
'url: "ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
// Output the content
|
||||
echo $body;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div width="100%" style="text-align:center;">
|
||||
<iframe width="1250" height="800" src="http://live.ircddb.net:8080/ircddblive5.html" style="border:0px #000000 solid; margin-top:30px;" align="center"></iframe>
|
||||
<iframe width="1250" height="800" src="./pgs/ircddb_proxy.php" style="border:0px #000000 solid; margin-top:30px; background-color:#ffffff;" align="center"></iframe>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,3 +1,20 @@
|
|||
xlx db v2.3.10
|
||||
Fix liveircddb page broken by CSP security headers
|
||||
|
||||
- "pgs/ircddb_proxy.php" (NEW)
|
||||
* Added transparent proxy for live.ircddb.net to resolve CSP and mixed-content issues
|
||||
* Proxies all requests through local server, rewriting URLs to maintain functionality
|
||||
* Supports both HTTP and HTTPS dashboard deployments
|
||||
* Defaults to live.ircddb.net:8080, configurable via $PageOptions['IRCDDB']['URL']
|
||||
* Default page ircddblive5.html, configurable via $PageOptions['IRCDDB']['Page']
|
||||
|
||||
- "pgs/liveircddb.php"
|
||||
* Changed iframe source from direct external URL to local proxy
|
||||
|
||||
- "pgs/config.inc.php"
|
||||
* Added $PageOptions['IRCDDB']['Show'] option
|
||||
* Added commented out optional override options for URL and Page
|
||||
|
||||
xlx db v2.3.9
|
||||
|
||||
SECURITY UPDATE - Minor upgrade to further improve dashboard security
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $PageOptions = array();
|
|||
|
||||
$PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address
|
||||
|
||||
$PageOptions['DashboardVersion'] = '2.3.9'; // Dashboard Version
|
||||
$PageOptions['DashboardVersion'] = '2.3.10'; // Dashboard Version
|
||||
|
||||
$PageOptions['PageRefreshActive'] = true; // Activate automatic refresh
|
||||
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
|
||||
|
|
@ -50,6 +50,10 @@ $PageOptions['MetaRobots'] = 'index,follow';
|
|||
|
||||
$PageOptions['UserPage']['ShowFilter'] = true; // Show Filter on Users page
|
||||
|
||||
$PageOptions['IRCDDB']['Show'] = true; // Show liveircddb menu option
|
||||
// $PageOptions['IRCDDB']['URL'] = 'http://live.ircddb.net:8080'; // Optional: Override ircddb server URL
|
||||
// $PageOptions['IRCDDB']['Page'] = 'ircddblive5.html'; // Optional: Override ircddb page
|
||||
|
||||
$Service['PIDFile'] = '/var/log/xlxd.pid';
|
||||
$Service['XMLFile'] = '/var/log/xlxd.xml';
|
||||
|
||||
|
|
|
|||
186
dashboard2/pgs/ircddb_proxy.php
Normal file
186
dashboard2/pgs/ircddb_proxy.php
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
/**
|
||||
* Transparent proxy for live.ircddb.net
|
||||
*
|
||||
* This proxy allows the ircddb live page to be embedded in the dashboard
|
||||
* without CSP or mixed-content issues. It fetches content from the upstream
|
||||
* server and rewrites URLs to route back through this proxy.
|
||||
*/
|
||||
|
||||
// Load config to get any overrides
|
||||
if (file_exists(__DIR__ . "/config.inc.php")) {
|
||||
require_once(__DIR__ . "/config.inc.php");
|
||||
}
|
||||
if (file_exists(__DIR__ . "/../config.inc.php")) {
|
||||
require_once(__DIR__ . "/../config.inc.php");
|
||||
}
|
||||
|
||||
// Defaults - can be overridden in config.inc.php
|
||||
$ircddbBaseUrl = $PageOptions['IRCDDB']['URL'] ?? 'http://live.ircddb.net:8080';
|
||||
$ircddbDefaultPage = $PageOptions['IRCDDB']['Page'] ?? 'ircddblive5.html';
|
||||
|
||||
// Security: Remove trailing slash from base URL
|
||||
$ircddbBaseUrl = rtrim($ircddbBaseUrl, '/');
|
||||
|
||||
// Get requested path, default to the main page
|
||||
$path = $_GET['path'] ?? $ircddbDefaultPage;
|
||||
|
||||
// Security: Sanitize path - only allow alphanumeric, dots, hyphens, underscores
|
||||
// This prevents directory traversal and other path-based attacks
|
||||
if (!preg_match('/^[a-zA-Z0-9._-]+$/', $path)) {
|
||||
http_response_code(400);
|
||||
die('Invalid path');
|
||||
}
|
||||
|
||||
// Security: Block potentially dangerous file extensions
|
||||
$blockedExtensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar'];
|
||||
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||||
if (in_array($extension, $blockedExtensions)) {
|
||||
http_response_code(403);
|
||||
die('Forbidden');
|
||||
}
|
||||
|
||||
// Build the upstream URL
|
||||
$upstreamUrl = $ircddbBaseUrl . '/' . $path;
|
||||
|
||||
// Forward query parameters (except 'path')
|
||||
$queryParams = $_GET;
|
||||
unset($queryParams['path']);
|
||||
if (!empty($queryParams)) {
|
||||
$upstreamUrl .= '?' . http_build_query($queryParams);
|
||||
}
|
||||
|
||||
// Fetch content - try cURL first, fall back to file_get_contents
|
||||
$body = false;
|
||||
$contentType = 'text/html';
|
||||
$httpCode = 200;
|
||||
$error = '';
|
||||
|
||||
if (function_exists('curl_init')) {
|
||||
// Use cURL if available
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $upstreamUrl,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_MAXREDIRS => 3,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_USERAGENT => 'XLX-Dashboard-Proxy/1.0',
|
||||
CURLOPT_HEADER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$error = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($response !== false && $httpCode > 0) {
|
||||
// Split headers and body
|
||||
$headers = substr($response, 0, $headerSize);
|
||||
$body = substr($response, $headerSize);
|
||||
|
||||
// Parse Content-Type from headers
|
||||
$headerLines = explode("\r\n", $headers);
|
||||
foreach ($headerLines as $header) {
|
||||
if (stripos($header, 'Content-Type:') === 0) {
|
||||
$contentType = trim(substr($header, 13));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to file_get_contents with stream context
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => "User-Agent: XLX-Dashboard-Proxy/1.0\r\n",
|
||||
'timeout' => 15,
|
||||
'follow_location' => true,
|
||||
'max_redirects' => 3,
|
||||
]
|
||||
]);
|
||||
|
||||
$body = @file_get_contents($upstreamUrl, false, $context);
|
||||
|
||||
if ($body !== false && isset($http_response_header)) {
|
||||
// Parse response headers
|
||||
foreach ($http_response_header as $header) {
|
||||
// Get HTTP status code
|
||||
if (preg_match('/^HTTP\/\d+\.\d+\s+(\d+)/', $header, $matches)) {
|
||||
$httpCode = (int)$matches[1];
|
||||
}
|
||||
// Get Content-Type
|
||||
if (stripos($header, 'Content-Type:') === 0) {
|
||||
$contentType = trim(substr($header, 13));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error = 'Failed to fetch upstream content';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if ($body === false) {
|
||||
http_response_code(502);
|
||||
die('Upstream server unavailable: ' . htmlspecialchars($error));
|
||||
}
|
||||
|
||||
// Forward the HTTP status code
|
||||
http_response_code($httpCode);
|
||||
|
||||
// Set content type
|
||||
header('Content-Type: ' . $contentType);
|
||||
|
||||
// Determine if we need to rewrite URLs in this content
|
||||
$rewriteContent = (
|
||||
stripos($contentType, 'text/html') !== false ||
|
||||
stripos($contentType, 'text/javascript') !== false ||
|
||||
stripos($contentType, 'application/javascript') !== false ||
|
||||
stripos($contentType, 'application/x-javascript') !== false
|
||||
);
|
||||
|
||||
if ($rewriteContent && !empty($body)) {
|
||||
// Rewrite relative URLs to go through this proxy
|
||||
// Handle src="file.js", href="file.css", url("file"), etc.
|
||||
|
||||
// Rewrite src attributes
|
||||
$body = preg_replace(
|
||||
'/src\s*=\s*"([^"\/][^"]*)"/',
|
||||
'src="ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
$body = preg_replace(
|
||||
"/src\s*=\s*'([^'\/][^']*)'/",
|
||||
"src='ircddb_proxy.php?path=\$1'",
|
||||
$body
|
||||
);
|
||||
|
||||
// Rewrite href attributes (for CSS, etc.)
|
||||
$body = preg_replace(
|
||||
'/href\s*=\s*"([^"\/][^"]*\.(css|ico))"/',
|
||||
'href="ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
$body = preg_replace(
|
||||
"/href\s*=\s*'([^'\/][^']*\.(css|ico))'/",
|
||||
"href='ircddb_proxy.php?path=\$1'",
|
||||
$body
|
||||
);
|
||||
|
||||
// Rewrite AJAX calls in JavaScript (the jj.yaws or jj3.yaws polling)
|
||||
// The original livelog.js uses: url: "jj.yaws", data: "p=" + lastNum
|
||||
// jQuery appends data as query string, so we need: url: "ircddb_proxy.php?path=jj.yaws"
|
||||
// Then jQuery will make it: ircddb_proxy.php?path=jj.yaws&p=123
|
||||
$body = preg_replace(
|
||||
'/url:\s*"(jj[0-9]*\.yaws)"/',
|
||||
'url: "ircddb_proxy.php?path=$1"',
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
// Output the content
|
||||
echo $body;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div width="100%" style="text-align:center;">
|
||||
<iframe width="1250" height="800" src="http://live.ircddb.net:8080/ircddblive5.html" style="border:0px #000000 solid; margin-top:30px;" align="center"></iframe>
|
||||
<iframe width="1250" height="800" src="./pgs/ircddb_proxy.php" style="border:0px #000000 solid; margin-top:30px; background-color:#ffffff;" align="center"></iframe>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in a new issue