From 55e169db498fe724c236113c8d2e9e1ad1856f75 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Wed, 16 Sep 2020 04:56:37 +0000
Subject: [PATCH] Configurable list of domains to ignore redirects

---
 src/Network/HTTPRequest.php | 19 +++++++++++++++++--
 src/Protocol/Feed.php       |  2 ++
 src/Util/Network.php        | 29 +++++++++++++++++++++++++++++
 static/defaults.config.php  |  4 ++++
 4 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/src/Network/HTTPRequest.php b/src/Network/HTTPRequest.php
index 79419d38e2..a615564763 100644
--- a/src/Network/HTTPRequest.php
+++ b/src/Network/HTTPRequest.php
@@ -192,7 +192,7 @@ class HTTPRequest implements IHTTPRequest
 
 		$curlResponse = new CurlResult($url, $s, $curl_info, curl_errno($ch), curl_error($ch));
 
-		if ($curlResponse->isRedirectUrl()) {
+		if (!Network::isRedirectBlocked($url) && $curlResponse->isRedirectUrl()) {
 			$redirects++;
 			$this->logger->notice('Curl redirect.', ['url' => $url, 'to' => $curlResponse->getRedirectUrl()]);
 			@curl_close($ch);
@@ -280,7 +280,7 @@ class HTTPRequest implements IHTTPRequest
 
 		$curlResponse = new CurlResult($url, $s, $curl_info, curl_errno($ch), curl_error($ch));
 
-		if ($curlResponse->isRedirectUrl()) {
+		if (!Network::isRedirectBlocked($url) && $curlResponse->isRedirectUrl()) {
 			$redirects++;
 			$this->logger->info('Post redirect.', ['url' => $url, 'to' => $curlResponse->getRedirectUrl()]);
 			curl_close($ch);
@@ -321,6 +321,11 @@ class HTTPRequest implements IHTTPRequest
 			return $url;
 		}
 
+		if (Network::isRedirectBlocked($url)) {
+			$this->logger->info('Domain should not be redirected.', ['url' => $url]);
+			return $url;
+		}
+
 		$url = Network::stripTrackingQueryParams($url);
 
 		if ($depth > 10) {
@@ -470,4 +475,14 @@ class HTTPRequest implements IHTTPRequest
 			DB_UPDATE_VERSION . '; ' .
 			$this->baseUrl;
 	}
+
+	private function redirectBlocked(string $url = null)
+	{
+		$hosts = $this->config->get('system', 'no_redirect_hosts');
+		if (empty($hosts)) {
+			return false;
+		}
+
+		$hostlist = explode(',', $hosts);
+	}
 }
diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php
index 6b73e7af09..560fe005e6 100644
--- a/src/Protocol/Feed.php
+++ b/src/Protocol/Feed.php
@@ -351,6 +351,8 @@ class Feed
 
 			$orig_plink = $item["plink"];
 
+			$item["plink"] = DI::httpRequest()->finalUrl($item["plink"]);
+
 			$item["parent-uri"] = $item["uri"];
 
 			$item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry);
diff --git a/src/Util/Network.php b/src/Util/Network.php
index 6694fd4f0c..ec1427003a 100644
--- a/src/Util/Network.php
+++ b/src/Util/Network.php
@@ -177,6 +177,35 @@ class Network
 		return false;
 	}
 
+	/**
+	 * Checks if the provided url is on the list of domains where redirects are blocked.
+	 * Returns true if it is or malformed URL, false if not.
+	 *
+	 * @param string $url The url to check the domain from
+	 *
+	 * @return boolean
+	 */
+	public static function isRedirectBlocked(string $url)
+	{
+		$host = @parse_url($url, PHP_URL_HOST);
+		if (!$host) {
+			return false;
+		}
+
+		$no_redirect_list = DI::config()->get('system', 'no_redirect_list', []);
+		if (!$no_redirect_list) {
+			return false;
+		}
+
+		foreach ($no_redirect_list as $no_redirect) {
+			if (fnmatch(strtolower($no_redirect), strtolower($host))) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
 	/**
 	 * Check if email address is allowed to register here.
 	 *
diff --git a/static/defaults.config.php b/static/defaults.config.php
index 35b1bc7b87..c1d6fff044 100644
--- a/static/defaults.config.php
+++ b/static/defaults.config.php
@@ -362,6 +362,10 @@ return [
 		// Don't use OEmbed to fetch more information about a link.
 		'no_oembed' => false,
 
+		// no_redirect_list (Array)
+		// List of domains where HTTP redirects should be ignored. 
+		'no_redirect_list' => [],
+
 		// no_smilies (Boolean)
 		// Don't show smilies.
 		'no_smilies' => false,
-- 
2.39.5