From a0490e36731957196648c674cf5e8e4f1d7d292d Mon Sep 17 00:00:00 2001
From: logmanoriginal <logmanoriginal@users.noreply.github.com>
Date: Sat, 10 Nov 2018 20:44:23 +0100
Subject: [PATCH] core: Add Debug::isEnabled() and Debug::isSecure()

Also adds documentation to Debug.php!

* Debug::isEnabled()

Checks if the DEBUG file exists on disk on the first call (stored in
memory for the duration of the instance). Returns true if debug mode
is enabled for the client.

This function also sets the internal flag for Debug::isSecure()!

* Debug::isSecure()

Returns true if debuging is enabled for specific IP addresses, false
otherwise. This is checked on the first call of Debug::isEnabled().
If you call this function before Debug::isEnabled(), the default value
is false.
---
 index.php          | 29 +----------------
 lib/BridgeList.php | 12 +++----
 lib/Debug.php      | 79 +++++++++++++++++++++++++++++++++++++++++++++-
 lib/contents.php   |  2 +-
 lib/rssbridge.php  |  1 +
 5 files changed, 87 insertions(+), 36 deletions(-)

diff --git a/index.php b/index.php
index 7b41586c..d57de89b 100644
--- a/index.php
+++ b/index.php
@@ -1,31 +1,4 @@
 <?php
-/*
-  Create a file named 'DEBUG' for enabling debug mode.
-  For further security, you may put whitelisted IP addresses in the file,
-  one IP per line. Empty file allows anyone(!).
-  Debugging allows displaying PHP error messages and bypasses the cache: this
-  can allow a malicious client to retrieve data about your server and hammer
-  a provider throught your rss-bridge instance.
-*/
-if(file_exists('DEBUG')) {
-	$debug_whitelist = trim(file_get_contents('DEBUG'));
-
-	$debug_enabled = empty($debug_whitelist)
-		|| in_array($_SERVER['REMOTE_ADDR'],
-			explode("\n", str_replace("\r", '', $debug_whitelist)
-		)
-	);
-
-	if($debug_enabled) {
-		ini_set('display_errors', '1');
-		error_reporting(E_ALL);
-		define('DEBUG', true);
-		if (empty($debug_whitelist)) {
-			define('DEBUG_INSECURE', true);
-		}
-	}
-}
-
 require_once __DIR__ . '/lib/rssbridge.php';
 
 Configuration::verifyInstallation();
@@ -221,7 +194,7 @@ try {
 
 		if($mtime !== false
 		&& (time() - $cache_timeout < $mtime)
-		&& (!defined('DEBUG') || DEBUG !== true)) { // Load cached data
+		&& !Debug::isEnabled()) { // Load cached data
 
 			// Send "Not Modified" response if client supports it
 			// Implementation based on https://stackoverflow.com/a/10847262
diff --git a/lib/BridgeList.php b/lib/BridgeList.php
index 4c59f106..b9454c37 100644
--- a/lib/BridgeList.php
+++ b/lib/BridgeList.php
@@ -57,16 +57,16 @@ EOD;
 	private static function getHeader() {
 		$warning = '';
 
-		if(defined('DEBUG') && DEBUG === true) {
-			if(defined('DEBUG_INSECURE') && DEBUG_INSECURE === true) {
+		if(Debug::isEnabled()) {
+			if(!Debug::isSecure()) {
 				$warning .= <<<EOD
-<section class="critical-warning">Warning : Debug mode is active from any location, 
-make sure only you can access RSS-Bridge.</section>
+<section class="critical-warning">Warning : Debug mode is active from any location,
+ make sure only you can access RSS-Bridge.</section>
 EOD;
 			} else {
 				$warning .= <<<EOD
-<section class="warning">Warning : Debug mode is active from your IP address, 
-your requests will bypass the cache.</section>
+<section class="warning">Warning : Debug mode is active from your IP address,
+ your requests will bypass the cache.</section>
 EOD;
 			}
 		}
diff --git a/lib/Debug.php b/lib/Debug.php
index 7d1f498d..0429f7eb 100644
--- a/lib/Debug.php
+++ b/lib/Debug.php
@@ -1,8 +1,85 @@
 <?php
 
+/**
+ * Implements functions for debugging purposes. Debugging can be enabled by
+ * placing a file named 'DEBUG' in PATH_ROOT.
+ *
+ * The file specifies a whitelist of IP addresses on which debug mode will be
+ * enabled. An empty file enables debug mode for everyone (highly discouraged
+ * for public servers!). Each line in the file specifies one client in the
+ * whitelist. For example:
+ *
+ * 192.168.1.72
+ * 127.0.0.1
+ * ::1
+ *
+ * Notice: If you are running RSS-Bridge on your local machine, you need to add
+ * localhost (either 127.0.0.1 for IPv4 or ::1 for IPv6) to your whitelist!
+ *
+ * Warning: In debug mode your server may display sensitive information! For
+ * security reasons it is recommended to whitelist only specific IP addresses.
+ */
 class Debug {
+
+	/**
+	 * Indicates if debug mode is enabled.
+	 * Use Debug::isEnabled() instead of accessing this parameter directly!
+	 */
+	private static $enabled = false;
+
+	/**
+	 * Indicates if debug mode is secure (not enabled for everyone).
+	 * Use Debug::isSecure() instead of accessing this parameter directly!
+	 */
+	private static $secure = false;
+
+	/**
+	 * @return bool Indicates if debug mode is enabled
+	 */
+	public static function isEnabled() {
+		static $firstCall = true; // Initialized on first call
+
+		if($firstCall && file_exists(PATH_ROOT . 'DEBUG')) {
+
+			$debug_whitelist = trim(file_get_contents(PATH_ROOT . 'DEBUG'));
+
+			Debug::$enabled = empty($debug_whitelist) || in_array($_SERVER['REMOTE_ADDR'],
+					explode("\n", str_replace("\r", '', $debug_whitelist)
+				)
+			);
+
+			if(Debug::$enabled) {
+				ini_set('display_errors', '1');
+				error_reporting(E_ALL);
+
+				Debug::$secure = !empty($debug_whitelist);
+			}
+
+			$firstCall = false; // Skip check on next call
+
+		}
+
+		return Debug::$enabled;
+	}
+
+	/**
+	 * Returns true if debug mode has been enabled for specific IP addresses
+	 * only, false otherwise.
+	 *
+	 * Notice: The security flag is set by Debug::isEnabled(). If this function
+	 * is called before Debug::isEnabled(), the default value is false!
+	 *
+	 * @return bool Indicates if debug mode is secure
+	 */
+	public static function isSecure() {
+		return Debug::$secure;
+	}
+
+	/**
+	 * Adds a debug message to error_log if debug mode is enabled
+	 */
 	public static function log($text) {
-		if(!DEBUG) {
+		if(!Debug::isEnabled()) {
 			return;
 		}
 
diff --git a/lib/contents.php b/lib/contents.php
index 4d17add1..fbd93f1b 100644
--- a/lib/contents.php
+++ b/lib/contents.php
@@ -123,7 +123,7 @@ $defaultSpanText = DEFAULT_SPAN_TEXT){
 	$time = $cache->getTime();
 	if($time !== false
 	&& (time() - $duration < $time)
-	&& (!defined('DEBUG') || DEBUG !== true)) { // Contents within duration
+	&& Debug::isEnabled()) { // Contents within duration
 		$content = $cache->loadData();
 	} else { // Content not within duration
 		$content = getContents($url, $header, $opts);
diff --git a/lib/rssbridge.php b/lib/rssbridge.php
index ac70580b..07812f2c 100644
--- a/lib/rssbridge.php
+++ b/lib/rssbridge.php
@@ -1,5 +1,6 @@
 <?php
 
+define('PATH_ROOT', __DIR__ . '/../'); // Path to root folder
 define('PATH_LIB', __DIR__ . '/../lib/'); // Path to core library
 define('PATH_LIB_VENDOR', __DIR__ . '/../vendor/'); // Path to vendor library
 define('PATH_LIB_BRIDGES', __DIR__ . '/../bridges/'); // Path to bridges library