From 5254147ccc18417f0b16ec4d8b8325d7790b4fde Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Mon, 23 Sep 2019 22:13:20 +0000
Subject: [PATCH] Fix "redir" loop

---
 boot.php               | 15 ++++++++--
 mod/photos.php         | 13 ++-------
 mod/redir.php          | 65 ++++++++++++++++++++++++++++++++++++++++--
 src/Content/Widget.php | 11 ++-----
 src/Core/Session.php   | 12 ++++++++
 src/Model/Profile.php  |  2 +-
 src/Util/Security.php  | 14 ++-------
 7 files changed, 93 insertions(+), 39 deletions(-)

diff --git a/boot.php b/boot.php
index 028ba1e829..4c9a1a5e8c 100644
--- a/boot.php
+++ b/boot.php
@@ -413,7 +413,7 @@ function public_contact()
  *
  * @return int|bool visitor_id or false
  */
-function remote_user()
+function remote_user($uid = 0)
 {
 	// You cannot be both local and remote.
 	// Unncommented by rabuzarus because remote authentication to local
@@ -422,13 +422,22 @@ function remote_user()
 //		return false;
 //	}
 
-	if (empty($_SESSION)) {
+	if (empty($_SESSION['authenticated'])) {
 		return false;
 	}
 
-	if (!empty($_SESSION['authenticated']) && !empty($_SESSION['visitor_id'])) {
+	if (!empty($uid) && !empty($_SESSION['remote'])) {
+		foreach ($_SESSION['remote'] as $visitor) {
+			if ($visitor['uid'] == $uid) {
+				return $visitor['cid'];
+			}
+		}
+	}
+
+	if (!empty($_SESSION['visitor_id'])) {
 		return intval($_SESSION['visitor_id']);
 	}
+
 	return false;
 }
 
diff --git a/mod/photos.php b/mod/photos.php
index fb43619b6e..50f40b248c 100644
--- a/mod/photos.php
+++ b/mod/photos.php
@@ -154,17 +154,8 @@ function photos_post(App $a)
 
 	if (local_user() && (local_user() == $page_owner_uid)) {
 		$can_post = true;
-	} elseif ($community_page && remote_user()) {
-		$contact_id = 0;
-
-		if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
-			foreach ($_SESSION['remote'] as $v) {
-				if ($v['uid'] == $page_owner_uid) {
-					$contact_id = $v['cid'];
-					break;
-				}
-			}
-		}
+	} elseif ($community_page && remote_user($page_owner_uid)) {
+		$contact_id = remote_user($page_owner_uid);
 
 		if ($contact_id > 0) {
 			if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $page_owner_uid, 'blocked' => false, 'pending' => false])) {
diff --git a/mod/redir.php b/mod/redir.php
index c99e1823c7..7c93c9f39a 100644
--- a/mod/redir.php
+++ b/mod/redir.php
@@ -15,16 +15,16 @@ function redir_init(App $a) {
 
 	$url = defaults($_GET, 'url', '');
 	$quiet = !empty($_GET['quiet']) ? '&quiet=1' : '';
-	$con_url = defaults($_GET, 'conurl', '');
 
 	if ($a->argc > 1 && intval($a->argv[1])) {
 		$cid = intval($a->argv[1]);
-	} elseif (local_user() && !empty($con_url)) {
-		$cid = Contact::getIdForURL($con_url, local_user());
 	} else {
 		$cid = 0;
 	}
 
+	// Try magic auth before the legacy stuff
+	redir_magic($a, $cid, $url);
+
 	if (!empty($cid)) {
 		$fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex', 'pending'];
 		$contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]);
@@ -140,3 +140,62 @@ function redir_init(App $a) {
 	notice(L10n::t('Contact not found.'));
 	$a->internalRedirect();
 }
+
+function redir_magic($a, $cid, $url)
+{
+	$visitor = Profile::getMyURL();
+	if (!empty($visitor)) {
+		Logger::info('Got my url', ['visitor' => $visitor]);
+	}
+
+	if (empty(visitor) && remote_user()) {
+		$contact = DBA::selectFirst('contact', ['url'], ['id' => remote_user()]);
+		if (!empty($contact['url'])) {
+			$visitor = $contact['url'];
+			Logger::info('Got remote user', ['visitor' => $visitor]);
+		}
+	}
+
+	if (empty(visitor) && local_user()) {
+		$contact = DBA::selectFirst('contact', ['url'], ['id' => local_user()]);
+		if (!empty($contact['url'])) {
+			$visitor = $contact['url'];
+			Logger::info('Got local user', ['visitor' => $visitor]);
+		}
+	}
+
+	$contact = DBA::selectFirst('contact', ['url'], ['id' => $cid]);
+	if (!DBA::isResult($contact)) {
+		Logger::info('Contact not found', ['id' => $cid]);
+		// Shouldn't happen under normal conditions
+		notice(L10n::t('Contact not found.'));
+		if (!empty($url)) {
+			$a->redirect($url);
+		} else {
+			$a->internalRedirect();
+		}
+	} else {
+		$contact_url = $contact['url'];
+		$target_url = defaults($url, $contact_url);
+	}
+
+	$basepath = Contact::getBasepath($contact_url);
+
+	// We don't use magic auth when there is no visitor, we are on the same system or we visit our own stuff
+	if (empty($visitor) || Strings::compareLink($basepath, System::baseUrl()) || Strings::compareLink($contact_url, $visitor)) {
+		Logger::info('Redirecting without magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
+		$a->redirect($target_url);
+	}
+
+	// Test for magic auth on the target system
+	$serverret = Network::curl($basepath . '/magic');
+	if ($serverret->isSuccess()) {
+		$separator = strpos($target_url, '?') ? '&' : '?';
+		$target_url .= $separator . 'zrl=' . urlencode($visitor);
+
+		Logger::info('Redirecting with magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
+		$a->redirect($target_url);
+	} else {
+		Logger::info('No magic for contact', ['contact' => $contact_url]);
+	}
+}
diff --git a/src/Content/Widget.php b/src/Content/Widget.php
index a1482ae943..9097442796 100644
--- a/src/Content/Widget.php
+++ b/src/Content/Widget.php
@@ -337,16 +337,9 @@ class Widget
 			return;
 		}
 
-		$cid = $zcid = 0;
+		$zcid = 0;
 
-		if (!empty($_SESSION['remote'])) {
-			foreach ($_SESSION['remote'] as $visitor) {
-				if ($visitor['uid'] == $profile_uid) {
-					$cid = $visitor['cid'];
-					break;
-				}
-			}
-		}
+		$cid = remote_user($profile_uid);
 
 		if (!$cid) {
 			if (Profile::getMyURL()) {
diff --git a/src/Core/Session.php b/src/Core/Session.php
index 22909a6e6e..8186c4745d 100644
--- a/src/Core/Session.php
+++ b/src/Core/Session.php
@@ -9,8 +9,10 @@ use Friendica\App;
 use Friendica\Core\Session\CacheSessionHandler;
 use Friendica\Core\Session\DatabaseSessionHandler;
 use Friendica\Database\DBA;
+use Friendica\Model\Contact;
 use Friendica\Model\User;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Strings;
 
 /**
  * High-level Session service class
@@ -120,6 +122,16 @@ class Session
 			'addr'          => defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0'),
 		]);
 
+		$remote_contacts = DBA::select('contact', ['id', 'uid'], ['nurl' => Strings::normaliseLink($_SESSION['my_url']), 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]);
+		while ($contact = DBA::fetch($remote_contacts)) {
+			if (($contact['uid'] == 0) || Contact::isBlockedByUser($contact['id'], $contact['uid'])) {
+				continue;
+			}
+
+			$_SESSION['remote'][] = ['cid' => $contact['id'], 'uid' => $contact['uid'], 'url' => $_SESSION['my_url']];
+		}
+		DBA::close($remote_contacts);
+
 		$member_since = strtotime($user_record['register_date']);
 		self::set('new_member', time() < ($member_since + ( 60 * 60 * 24 * 14)));
 
diff --git a/src/Model/Profile.php b/src/Model/Profile.php
index 9ea22a65ee..37f7028a51 100644
--- a/src/Model/Profile.php
+++ b/src/Model/Profile.php
@@ -248,7 +248,7 @@ class Profile
 	 */
 	public static function getByNickname($nickname, $uid = 0, $profile_id = 0)
 	{
-		if (remote_user() && !empty($_SESSION['remote'])) {
+		if (remote_user($uid) && !empty($_SESSION['remote'])) {
 			foreach ($_SESSION['remote'] as $visitor) {
 				if ($visitor['uid'] == $uid) {
 					$contact = DBA::selectFirst('contact', ['profile-id'], ['id' => $visitor['cid']]);
diff --git a/src/Util/Security.php b/src/Util/Security.php
index 1c934d6fe6..0c09b745d8 100644
--- a/src/Util/Security.php
+++ b/src/Util/Security.php
@@ -33,7 +33,7 @@ class Security extends BaseObject
 			return true;
 		}
 
-		if (remote_user()) {
+		if (remote_user($owner)) {
 			// use remembered decision and avoid a DB lookup for each and every display item
 			// DO NOT use this function if there are going to be multiple owners
 			// We have a contact-id for an authenticated remote user, this block determines if the contact
@@ -44,17 +44,7 @@ class Security extends BaseObject
 			} elseif ($verified === 1) {
 				return false;
 			} else {
-				$cid = 0;
-
-				if (!empty($_SESSION['remote'])) {
-					foreach ($_SESSION['remote'] as $visitor) {
-						if ($visitor['uid'] == $owner) {
-							$cid = $visitor['cid'];
-							break;
-						}
-					}
-				}
-
+				$cid = remote_user($owner);
 				if (!$cid) {
 					return false;
 				}
-- 
2.39.5