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\FixtureTest;
27 use GuzzleHttp\Middleware;
29 class ProbeTest extends FixtureTest
31 use DiceHttpMockHandlerTrait;
33 protected function setUp(): void
37 $this->setupHttpMockHandler();
40 const TEMPLATENOBASE = '
44 <title>Example Blog</title>
45 <link href="{{$link}}" rel="alternate" type="application/rss+xml" title="Example Blog" />
46 <link href="{{$link}}" rel="feed" type="application/rss+xml" title="Example Blog" />
53 const TEMPLATEBASE = '
57 <title>Example Blog</title>
58 <link href="{{$link}}" rel="alternate" type="application/rss+xml" title="Example Blog" />
59 <link href="{{$link}}" rel="feed" type="application/rss+xml" title="Example Blog" />
60 <base href="{{$url}}">
68 'https://example.org/path/to/blog/index.php' => [
69 'index.xml' => 'https://example.org/path/to/blog/index.xml',
70 './index.xml' => 'https://example.org/path/to/blog/index.xml',
71 '../index.xml' => 'https://example.org/path/to/index.xml',
72 '/index.xml' => 'https://example.org/index.xml',
73 '//example.com/index.xml' => 'https://example.com/index.xml',
75 'https://example.org/path/to/blog/' => [
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/blog/' => [
83 'index.xml' => 'https://example.org/blog/index.xml',
84 './index.xml' => 'https://example.org/blog/index.xml',
85 '../index.xml' => 'https://example.org/index.xml',
86 '/index.xml' => 'https://example.org/index.xml',
87 '//example.com/index.xml' => 'https://example.com/index.xml',
89 'https://example.org' => [
90 'index.xml' => 'https://example.org/index.xml',
91 './index.xml' => 'https://example.org/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',
98 private function replaceMacros($template, $vars)
100 foreach ($vars as $var => $value) {
101 $template = str_replace('{{' . $var . '}}', $value, $template);
110 public function testGetFeedLinkNoBase()
112 foreach (self::EXPECTED as $url => $hrefs) {
113 foreach ($hrefs as $href => $expected) {
114 $body = $this->replaceMacros(self::TEMPLATENOBASE, ['$link' => $href]);
116 $feedLink = Probe::getFeedLink($url, $body);
118 self::assertEquals($expected, $feedLink, 'base url = ' . $url . ' | href = ' . $href);
126 public function testGetFeedLinkBase()
128 foreach (self::EXPECTED as $url => $hrefs) {
129 foreach ($hrefs as $href => $expected) {
130 $body = $this->replaceMacros(self::TEMPLATEBASE, ['$url' => $url, '$link' => $href]);
132 $feedLink = Probe::getFeedLink('http://example.com', $body);
134 self::assertEquals($expected, $feedLink, 'base url = ' . $url . ' | href = ' . $href);
139 public function dataCleanUri(): array
143 'expected' => 'Artists4Future_Muenchen@climatejustice.global',
144 'uri' => '@Artists4Future_Muenchen@climatejustice.global',
146 'no-scheme-no-fragment' => [
147 'expected' => 'example.com/path?arg=value',
148 'uri' => 'example.com/path?arg=value',
150 /* This case makes little sense, both in our expectation of receiving it in any context and in the way we
151 * do not change it in Probe::cleanUri, but it doesn't seem to be the source of any terrible security hole.
153 'no-scheme-fragment' => [
154 'expected' => 'example.com/path?arg=value#fragment',
155 'uri' => 'example.com/path?arg=value#fragment',
157 'scheme-no-fragment' => [
158 'expected' => 'https://example.com/path?arg=value',
159 'uri' => 'https://example.com/path?arg=value#fragment',
161 'scheme-fragment' => [
162 'expected' => 'https://example.com/path?arg=value',
163 'uri' => 'https://example.com/path?arg=value#fragment',
169 * @dataProvider dataCleanUri
171 public function testCleanUri(string $expected, string $uri)
173 self::assertEquals($expected, Probe::cleanURI($uri));
176 public function dataUri(): array
179 'Artists4Future_Muenchen@climatejustice.global' => [
180 'uri' => 'Artists4Future_Muenchen@climatejustice.global',
182 'name' => 'Artists4Future München',
183 'nick' => 'Artists4Future_Muenchen',
184 'url' => 'https://climatejustice.global/users/Artists4Future_Muenchen',
185 'alias' => 'https://climatejustice.global/@Artists4Future_Muenchen',
186 'photo' => 'https://cdn.masto.host/climatejusticeglobal/accounts/avatars/000/021/220/original/05ee9e827a5b47fc.jpg',
187 'header' => 'https://cdn.masto.host/climatejusticeglobal/accounts/headers/000/021/220/original/9b98b75cf696cd11.jpg',
189 '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.',
191 'batch' => 'https://climatejustice.global/inbox',
192 'notify' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
193 'poll' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
194 'subscribe' => 'https://climatejustice.global/authorize_interaction?uri={uri}',
195 'following' => 'https://climatejustice.global/users/Artists4Future_Muenchen/following',
196 'followers' => 'https://climatejustice.global/users/Artists4Future_Muenchen/followers',
197 'inbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
198 'outbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
199 'sharedinbox' => 'https://climatejustice.global/inbox',
202 'pubkey' => '-----BEGIN PUBLIC KEY-----
203 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6pYKPuDKb+rmBB869uPV
204 uLYFPosGxMUfenWqfWmFKzEqJ87rAft0IQDAL6dCoYE55ov/lEDNROhasTZLirZf
205 M5b7/1JmwMrAfEiaciuYqDWT3/yDpnekOIdzP5iSClg4zt7e6HRFuClqo4+b6hIE
206 DTMV4ksItvq/92MIu62pZ2SZr5ADPPZ/914lJ86hIH5BanbE8ZFzDS9vJA7V74rt
207 Vvkr5c/OiUyuODNYApSl87Ez8cuj8Edt89YWkDCajQn3EkmXGeJY/VRjEDfcyk6r
208 AvdUa0ArjXud3y3NkakVFZ0d7tmB20Vn9s/CfYHU8FXzbI1kFkov2BX899VVP5Ay
210 -----END PUBLIC KEY-----',
211 'manually-approve' => 0,
212 'baseurl' => 'https://climatejustice.global',
219 * @dataProvider dataUri
221 public function testProbeUri(string $uri, array $assertInfos)
223 self::markTestIncomplete('hard work due mocking 19 different http-requests');
228 * GET : https://climatejustice.global/.well-known/webfinger?resource=acct:Artists4Future_Muenchen%40climatejustice.global
230 * GET : http://localhost/.well-known/nodeinfo
232 * GET : http://localhost/statistics.json
234 * GET : http://localhost
236 * GET : http://localhost/friendica/json
238 * GET : http://localhost/friendika/json
240 * GET : http://localhost/poco
242 * GET : http://localhost/api/v1/directory?limit=1
244 * GET : http://localhost/.well-known/x-social-relay
246 * GET : http://localhost/friendica
248 * GET : https://climatejustice.global/users/Artists4Future_Muenchen
250 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/following
252 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/followers
254 * GET : https://climatejustice.global/users/Artists4Future_Muenchen/outbox
256 * GET : https://climatejustice.global/.well-known/nodeinfo
258 * GET : https://climatejustice.global/nodeinfo/2.0
260 * GET : https://climatejustice.global/poco
262 * GET : https://climatejustice.global/api/v1/directory?limit=1
264 * GET : https://climatejustice.global/.well-known/webfinger?resource=acct%3AArtists4Future_Muenchen%40climatejustice.global
270 $history = Middleware::history($container);
272 $this->httpRequestHandler->push($history);
274 self::assertArraySubset($assertInfos, Probe::uri($uri, '', 0));
276 // Iterate over the requests and responses
277 foreach ($container as $transaction) {
278 echo $transaction['request']->getMethod() . " : " . $transaction['request']->getUri() . PHP_EOL;
280 if ($transaction['response']) {
281 echo $transaction['response']->getStatusCode() . PHP_EOL;
283 } elseif ($transaction['error']) {
284 echo $transaction['error'];