]> git.mxchange.org Git - friendica.git/blob - mod/redir.php
Add follow/unfollow link to the contact actions menu
[friendica.git] / mod / redir.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 use Friendica\App;
23 use Friendica\Core\Logger;
24 use Friendica\Core\System;
25 use Friendica\Database\DBA;
26 use Friendica\DI;
27 use Friendica\Model\Contact;
28 use Friendica\Model\Profile;
29 use Friendica\Network\HTTPClient\Client\HttpClientAccept;
30 use Friendica\Network\HTTPClient\Client\HttpClientOptions;
31 use Friendica\Util\Strings;
32
33 function redir_init(App $a) {
34         if (!DI::userSession()->isAuthenticated()) {
35                 throw new \Friendica\Network\HTTPException\ForbiddenException(DI::l10n()->t('Access denied.'));
36         }
37
38         $url = $_GET['url'] ?? '';
39
40         if (DI::args()->getArgc() > 1 && intval(DI::args()->getArgv()[1])) {
41                 $cid = intval(DI::args()->getArgv()[1]);
42         } else {
43                 $cid = 0;
44         }
45
46         // Try magic auth before the legacy stuff
47         redir_magic($a, $cid, $url);
48
49         if (empty($cid)) {
50                 throw new \Friendica\Network\HTTPException\BadRequestException(DI::l10n()->t('Bad Request.'));
51         }
52
53         $fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name'];
54         $contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, DI::userSession()->getLocalUserId()]]);
55         if (!DBA::isResult($contact)) {
56                 throw new \Friendica\Network\HTTPException\NotFoundException(DI::l10n()->t('Contact not found.'));
57         }
58
59         $contact_url = $contact['url'];
60
61         if (!empty($a->getContactId()) && $a->getContactId() == $cid) {
62                 // Local user is already authenticated.
63                 redir_check_url($contact_url, $url);
64                 $a->redirect($url ?: $contact_url);
65         }
66
67         if ($contact['uid'] == 0 && DI::userSession()->getLocalUserId()) {
68                 // Let's have a look if there is an established connection
69                 // between the public contact we have found and the local user.
70                 $contact = DBA::selectFirst('contact', $fields, ['nurl' => $contact['nurl'], 'uid' => DI::userSession()->getLocalUserId()]);
71
72                 if (DBA::isResult($contact)) {
73                         $cid = $contact['id'];
74                 }
75
76                 if (!empty($a->getContactId()) && $a->getContactId() == $cid) {
77                         // Local user is already authenticated.
78                         redir_check_url($contact_url, $url);
79                         $target_url = $url ?: $contact_url;
80                         Logger::info($contact['name'] . " is already authenticated. Redirecting to " . $target_url);
81                         $a->redirect($target_url);
82                 }
83         }
84
85         if (DI::userSession()->getRemoteUserId()) {
86                 $host = substr(DI::baseUrl()->getUrlPath() . (DI::baseUrl()->getUrlPath() ? '/' . DI::baseUrl()->getUrlPath() : ''), strpos(DI::baseUrl()->getUrlPath(), '://') + 3);
87                 $remotehost = substr($contact['addr'], strpos($contact['addr'], '@') + 1);
88
89                 // On a local instance we have to check if the local user has already authenticated
90                 // with the local contact. Otherwise the local user would ask the local contact
91                 // for authentification everytime he/she is visiting a profile page of the local
92                 // contact.
93                 if (($host == $remotehost) && (DI::userSession()->getRemoteContactID(DI::session()->get('visitor_visiting')) == DI::session()->get('visitor_id'))) {
94                         // Remote user is already authenticated.
95                         redir_check_url($contact_url, $url);
96                         $target_url = $url ?: $contact_url;
97                         Logger::info($contact['name'] . " is already authenticated. Redirecting to " . $target_url);
98                         $a->redirect($target_url);
99                 }
100         }
101
102         if (empty($url)) {
103                 throw new \Friendica\Network\HTTPException\BadRequestException(DI::l10n()->t('Bad Request.'));
104         }
105
106         // If we don't have a connected contact, redirect with
107         // the 'zrl' parameter.
108         $my_profile = Profile::getMyURL();
109
110         if (!empty($my_profile) && !Strings::compareLink($my_profile, $url)) {
111                 $separator = strpos($url, '?') ? '&' : '?';
112
113                 $url .= $separator . 'zrl=' . urlencode($my_profile);
114         }
115
116         Logger::info('redirecting to ' . $url);
117         $a->redirect($url);
118 }
119
120 function redir_magic($a, $cid, $url)
121 {
122         $visitor = Profile::getMyURL();
123         if (!empty($visitor)) {
124                 Logger::info('Got my url', ['visitor' => $visitor]);
125         }
126
127         $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid]);
128         if (!DBA::isResult($contact)) {
129                 Logger::info('Contact not found', ['id' => $cid]);
130                 throw new \Friendica\Network\HTTPException\NotFoundException(DI::l10n()->t('Contact not found.'));
131         } else {
132                 $contact_url = $contact['url'];
133                 redir_check_url($contact_url, $url);
134                 $target_url = $url ?: $contact_url;
135         }
136
137         $basepath = Contact::getBasepath($contact_url);
138
139         // We don't use magic auth when there is no visitor, we are on the same system or we visit our own stuff
140         if (empty($visitor) || Strings::compareLink($basepath, DI::baseUrl()) || Strings::compareLink($contact_url, $visitor)) {
141                 Logger::info('Redirecting without magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
142                 DI::app()->redirect($target_url);
143         }
144
145         // Test for magic auth on the target system
146         $serverret = DI::httpClient()->head($basepath . '/magic', [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::HTML]);
147         if ($serverret->isSuccess()) {
148                 $separator = strpos($target_url, '?') ? '&' : '?';
149                 $target_url .= $separator . 'zrl=' . urlencode($visitor) . '&addr=' . urlencode($contact_url);
150
151                 Logger::info('Redirecting with magic', ['target' => $target_url, 'visitor' => $visitor, 'contact' => $contact_url]);
152                 System::externalRedirect($target_url);
153         } else {
154                 Logger::info('No magic for contact', ['contact' => $contact_url]);
155         }
156 }
157
158 function redir_check_url(string $contact_url, string $url)
159 {
160         if (empty($contact_url) || empty($url)) {
161                 return;
162         }
163
164         $url_host = parse_url($url, PHP_URL_HOST);
165         if (empty($url_host)) {
166                 $url_host = parse_url(DI::baseUrl(), PHP_URL_HOST);
167         }
168
169         $contact_url_host = parse_url($contact_url, PHP_URL_HOST);
170
171         if ($url_host == $contact_url_host) {
172                 return;
173         }
174
175         Logger::error('URL check host mismatch', ['contact' => $contact_url, 'url' => $url]);
176         throw new \Friendica\Network\HTTPException\ForbiddenException(DI::l10n()->t('Access denied.'));
177 }