3 * @copyright Copyright (C) 2010-2023, the Friendica project
5 * @license GNU AGPL version 3 or any later version
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.
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.
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/>.
22 namespace Friendica\Test\src\Network;
24 use Friendica\Network\Probe;
25 use Friendica\Test\DiceHttpMockHandlerTrait;
26 use Friendica\Test\MockedTest;
27 use GuzzleHttp\Middleware;
29 class ProbeTest extends MockedTest
31 use DiceHttpMockHandlerTrait;
33 protected function setUp(): void
37 $this->setupHttpMockHandler();
40 protected function tearDown(): void
42 $this->tearDownHandler();
47 const TEMPLATENOBASE = '
51 <title>Example Blog</title>
52 <link href="{{$link}}" rel="alternate" type="application/rss+xml" title="Example Blog" />
53 <link href="{{$link}}" rel="feed" type="application/rss+xml" title="Example Blog" />
60 const TEMPLATEBASE = '
64 <title>Example Blog</title>
65 <link href="{{$link}}" rel="alternate" type="application/rss+xml" title="Example Blog" />
66 <link href="{{$link}}" rel="feed" type="application/rss+xml" title="Example Blog" />
67 <base href="{{$url}}">
75 'https://example.org/path/to/blog/index.php' => [
76 'index.xml' => 'https://example.org/path/to/blog/index.xml',
77 './index.xml' => 'https://example.org/path/to/blog/index.xml',
78 '../index.xml' => 'https://example.org/path/to/index.xml',
79 '/index.xml' => 'https://example.org/index.xml',
80 '//example.com/index.xml' => 'https://example.com/index.xml',
82 'https://example.org/path/to/blog/' => [
83 'index.xml' => 'https://example.org/path/to/blog/index.xml',
84 './index.xml' => 'https://example.org/path/to/blog/index.xml',
85 '../index.xml' => 'https://example.org/path/to/index.xml',
86 '/index.xml' => 'https://example.org/index.xml',
87 '//example.com/index.xml' => 'https://example.com/index.xml',
89 'https://example.org/blog/' => [
90 'index.xml' => 'https://example.org/blog/index.xml',
91 './index.xml' => 'https://example.org/blog/index.xml',
92 '../index.xml' => 'https://example.org/index.xml',
93 '/index.xml' => 'https://example.org/index.xml',
94 '//example.com/index.xml' => 'https://example.com/index.xml',
96 'https://example.org' => [
97 'index.xml' => 'https://example.org/index.xml',
98 './index.xml' => 'https://example.org/index.xml',
99 '../index.xml' => 'https://example.org/index.xml',
100 '/index.xml' => 'https://example.org/index.xml',
101 '//example.com/index.xml' => 'https://example.com/index.xml',
105 private function replaceMacros($template, $vars)
107 foreach ($vars as $var => $value) {
108 $template = str_replace('{{' . $var . '}}', $value, $template);
117 public function testGetFeedLinkNoBase()
119 foreach (self::EXPECTED as $url => $hrefs) {
120 foreach ($hrefs as $href => $expected) {
121 $body = $this->replaceMacros(self::TEMPLATENOBASE, ['$link' => $href]);
123 $feedLink = Probe::getFeedLink($url, $body);
125 self::assertEquals($expected, $feedLink, 'base url = ' . $url . ' | href = ' . $href);
133 public function testGetFeedLinkBase()
135 foreach (self::EXPECTED as $url => $hrefs) {
136 foreach ($hrefs as $href => $expected) {
137 $body = $this->replaceMacros(self::TEMPLATEBASE, ['$url' => $url, '$link' => $href]);
139 $feedLink = Probe::getFeedLink('http://example.com', $body);
141 self::assertEquals($expected, $feedLink, 'base url = ' . $url . ' | href = ' . $href);
146 public function dataCleanUri(): array
150 'expected' => 'Artists4Future_Muenchen@climatejustice.global',
151 'uri' => '@Artists4Future_Muenchen@climatejustice.global',
153 'no-scheme-no-fragment' => [
154 'expected' => 'example.com/path?arg=value',
155 'uri' => 'example.com/path?arg=value',
157 /* This case makes little sense, both in our expectation of receiving it in any context and in the way we
158 * do not change it in Probe::cleanUri, but it doesn't seem to be the source of any terrible security hole.
160 'no-scheme-fragment' => [
161 'expected' => 'example.com/path?arg=value#fragment',
162 'uri' => 'example.com/path?arg=value#fragment',
164 'scheme-no-fragment' => [
165 'expected' => 'https://example.com/path?arg=value',
166 'uri' => 'https://example.com/path?arg=value#fragment',
168 'scheme-fragment' => [
169 'expected' => 'https://example.com/path?arg=value',
170 'uri' => 'https://example.com/path?arg=value#fragment',
176 * @dataProvider dataCleanUri
178 public function testCleanUri(string $expected, string $uri)
180 self::assertEquals($expected, Probe::cleanURI($uri));
183 public function dataUri(): array
186 'Artists4Future_Muenchen@climatejustice.global' => [
187 'uri' => 'Artists4Future_Muenchen@climatejustice.global',
189 'name' => 'Artists4Future München',
190 'nick' => 'Artists4Future_Muenchen',
191 'url' => 'https://climatejustice.global/users/Artists4Future_Muenchen',
192 'alias' => 'https://climatejustice.global/@Artists4Future_Muenchen',
193 'photo' => 'https://cdn.masto.host/climatejusticeglobal/accounts/avatars/000/021/220/original/05ee9e827a5b47fc.jpg',
194 'header' => 'https://cdn.masto.host/climatejusticeglobal/accounts/headers/000/021/220/original/9b98b75cf696cd11.jpg',
196 'about' => 'Wir sind Künstler oder einfach gerne kreativ tätig und setzen uns unabhängig von politischen Parteien für den Klimaschutz ein. Die Bedingungen zu schaffen, die die [url=https://climatejustice.global/tags/Klimakrise]#Klimakrise[/url] verhindern/eindämmen (gemäß den Forderungen der [url=https://climatejustice.global/tags/Fridays4Future]#Fridays4Future[/url]) ist Aufgabe der Politik, muss aber gesamtgesellschaftlich getragen werden. Mit unseren künstlerischen Aktionen wollen wir einen anderen Zugang anbieten für wissenschaftlich rationale Argumente, speziell zur Erderwärmung und ihre Konsequenzen.',
198 'batch' => 'https://climatejustice.global/inbox',
199 'notify' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
200 'poll' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
201 'subscribe' => 'https://climatejustice.global/authorize_interaction?uri={uri}',
202 'following' => 'https://climatejustice.global/users/Artists4Future_Muenchen/following',
203 'followers' => 'https://climatejustice.global/users/Artists4Future_Muenchen/followers',
204 'inbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
205 'outbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
206 'sharedinbox' => 'https://climatejustice.global/inbox',
209 'pubkey' => '-----BEGIN PUBLIC KEY-----
210 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6pYKPuDKb+rmBB869uPV
211 uLYFPosGxMUfenWqfWmFKzEqJ87rAft0IQDAL6dCoYE55ov/lEDNROhasTZLirZf
212 M5b7/1JmwMrAfEiaciuYqDWT3/yDpnekOIdzP5iSClg4zt7e6HRFuClqo4+b6hIE
213 DTMV4ksItvq/92MIu62pZ2SZr5ADPPZ/914lJ86hIH5BanbE8ZFzDS9vJA7V74rt
214 Vvkr5c/OiUyuODNYApSl87Ez8cuj8Edt89YWkDCajQn3EkmXGeJY/VRjEDfcyk6r
215 AvdUa0ArjXud3y3NkakVFZ0d7tmB20Vn9s/CfYHU8FXzbI1kFkov2BX899VVP5Ay
217 -----END PUBLIC KEY-----',
218 'manually-approve' => 0,
219 'baseurl' => 'https://climatejustice.global',
226 * @dataProvider dataUri
228 public function testProbeUri(string $uri, array $assertInfos)
230 self::markTestIncomplete('hard work due mocking 19 different http-requests');
235 * GET : https://climatejustice.global/.well-known/webfinger?resource=acct:Artists4Future_Muenchen%40climatejustice.global
237 * GET : http://localhost/.well-known/nodeinfo
239 * GET : http://localhost/statistics.json
241 * GET : http://localhost
243 * GET : http://localhost/friendica/json
245 * GET : http://localhost/friendika/json
247 * GET : http://localhost/poco
249 * GET : http://localhost/api/v1/directory?limit=1
251 * GET : http://localhost/.well-known/x-social-relay
253 * GET : http://localhost/friendica
255 * GET : https://climatejustice.global/users/Artists4Future_Muenchen
257 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/following
259 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/followers
261 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/outbox
263 * GET : https://climatejustice.global/.well-known/nodeinfo
265 * GET : https://climatejustice.global/nodeinfo/2.0
267 * GET : https://climatejustice.global/poco
269 * GET : https://climatejustice.global/api/v1/directory?limit=1
271 * GET : https://climatejustice.global/.well-known/webfinger?resource=acct%3AArtists4Future_Muenchen%40climatejustice.global
277 $history = Middleware::history($container);
279 $this->httpRequestHandler->push($history);
281 self::assertArraySubset($assertInfos, Probe::uri($uri, '', 0));
283 // Iterate over the requests and responses
284 foreach ($container as $transaction) {
285 echo $transaction['request']->getMethod() . " : " . $transaction['request']->getUri() . PHP_EOL;
287 if ($transaction['response']) {
288 echo $transaction['response']->getStatusCode() . PHP_EOL;
290 } elseif ($transaction['error']) {
291 echo $transaction['error'];