diff --git a/dashboard2/changes.txt b/dashboard2/changes.txt index 40d6de0..327f769 100644 --- a/dashboard2/changes.txt +++ b/dashboard2/changes.txt @@ -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 diff --git a/dashboard2/pgs/config.inc.php b/dashboard2/pgs/config.inc.php index 1bb5b25..124b786 100644 --- a/dashboard2/pgs/config.inc.php +++ b/dashboard2/pgs/config.inc.php @@ -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'; diff --git a/dashboard2/pgs/ircddb_proxy.php b/dashboard2/pgs/ircddb_proxy.php new file mode 100644 index 0000000..fee4fb0 --- /dev/null +++ b/dashboard2/pgs/ircddb_proxy.php @@ -0,0 +1,186 @@ + $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; diff --git a/dashboard2/pgs/liveircddb.php b/dashboard2/pgs/liveircddb.php index 0e1dc37..5e77f4d 100644 --- a/dashboard2/pgs/liveircddb.php +++ b/dashboard2/pgs/liveircddb.php @@ -1,4 +1,4 @@
- +
\ No newline at end of file