]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/InstallerTest.php
BaseURL hardening
[friendica.git] / tests / src / Core / InstallerTest.php
1 <?php
2
3 // this is in the same namespace as Install for mocking 'function_exists'
4 namespace Friendica\Core;
5
6 use Friendica\Network\CurlResult;
7 use Friendica\Object\Image;
8 use Friendica\Test\MockedTest;
9 use Friendica\Test\Util\L10nMockTrait;
10 use Friendica\Test\Util\VFSTrait;
11 use Friendica\Util\Network;
12
13 /**
14  * @runTestsInSeparateProcesses
15  * @preserveGlobalState disabled
16  */
17 class InstallerTest extends MockedTest
18 {
19         use VFSTrait;
20         use L10nMockTrait;
21
22         public function setUp()
23         {
24                 parent::setUp();
25
26                 $this->setUpVfsDir();
27         }
28
29         /**
30          * Mocking the L10n::t() calls for the function checks
31          */
32         private function mockFunctionL10TCalls()
33         {
34                 $this->mockL10nT('Apache mod_rewrite module', 1);
35                 $this->mockL10nT('PDO or MySQLi PHP module', 1);
36                 $this->mockL10nT('libCurl PHP module', 1);
37                 $this->mockL10nT('Error: libCURL PHP module required but not installed.', 1);
38                 $this->mockL10nT('XML PHP module', 1);
39                 $this->mockL10nT('GD graphics PHP module', 1);
40                 $this->mockL10nT('Error: GD graphics PHP module with JPEG support required but not installed.', 1);
41                 $this->mockL10nT('OpenSSL PHP module', 1);
42                 $this->mockL10nT('Error: openssl PHP module required but not installed.', 1);
43                 $this->mockL10nT('mb_string PHP module', 1);
44                 $this->mockL10nT('Error: mb_string PHP module required but not installed.', 1);
45                 $this->mockL10nT('iconv PHP module', 1);
46                 $this->mockL10nT('Error: iconv PHP module required but not installed.', 1);
47                 $this->mockL10nT('POSIX PHP module', 1);
48                 $this->mockL10nT('Error: POSIX PHP module required but not installed.', 1);
49                 $this->mockL10nT('JSON PHP module', 1);
50                 $this->mockL10nT('Error: JSON PHP module required but not installed.', 1);
51                 $this->mockL10nT('File Information PHP module', 1);
52                 $this->mockL10nT('Error: File Information PHP module required but not installed.', 1);
53         }
54
55         private function assertCheckExist($position, $title, $help, $status, $required, $assertionArray)
56         {
57                 $this->assertArraySubset([$position => [
58                         'title' => $title,
59                         'status' => $status,
60                         'required' => $required,
61                         'error_msg' => null,
62                         'help' => $help]
63                 ], $assertionArray);
64         }
65
66         /**
67          * Replaces function_exists results with given mocks
68          *
69          * @param array $functions a list from function names and their result
70          */
71         private function setFunctions($functions)
72         {
73                 global $phpMock;
74                 $phpMock['function_exists'] = function($function) use ($functions) {
75                         foreach ($functions as $name => $value) {
76                                 if ($function == $name) {
77                                         return $value;
78                                 }
79                         }
80                         return '__phpunit_continue__';
81                 };
82         }
83
84         /**
85          * Replaces class_exist results with given mocks
86          *
87          * @param array $classes a list from class names and their results
88          */
89         private function setClasses($classes)
90         {
91                 global $phpMock;
92                 $phpMock['class_exists'] = function($class) use ($classes) {
93                         foreach ($classes as $name => $value) {
94                                 if ($class == $name) {
95                                         return $value;
96                                 }
97                         }
98                         return '__phpunit_continue__';
99                 };
100         }
101
102         /**
103          * @small
104          */
105         public function testCheckKeys()
106         {
107                 $this->mockL10nT();
108
109                 $this->setFunctions(['openssl_pkey_new' => false]);
110                 $install = new Installer();
111                 $this->assertFalse($install->checkKeys());
112
113                 $this->setFunctions(['openssl_pkey_new' => true]);
114                 $install = new Installer();
115                 $this->assertTrue($install->checkKeys());
116         }
117
118         /**
119          * @small
120          */
121         public function testCheckFunctions()
122         {
123                 $this->mockFunctionL10TCalls();
124                 $this->setFunctions(['curl_init' => false, 'imagecreatefromjpeg' => true]);
125                 $install = new Installer();
126                 $this->assertFalse($install->checkFunctions());
127                 $this->assertCheckExist(3,
128                         'libCurl PHP module',
129                         'Error: libCURL PHP module required but not installed.',
130                         false,
131                         true,
132                         $install->getChecks());
133
134                 $this->mockFunctionL10TCalls();
135                 $this->setFunctions(['imagecreatefromjpeg' => false]);
136                 $install = new Installer();
137                 $this->assertFalse($install->checkFunctions());
138                 $this->assertCheckExist(4,
139                         'GD graphics PHP module',
140                         'Error: GD graphics PHP module with JPEG support required but not installed.',
141                         false,
142                         true,
143                         $install->getChecks());
144
145                 $this->mockFunctionL10TCalls();
146                 $this->setFunctions(['openssl_public_encrypt' => false]);
147                 $install = new Installer();
148                 $this->assertFalse($install->checkFunctions());
149                 $this->assertCheckExist(5,
150                         'OpenSSL PHP module',
151                         'Error: openssl PHP module required but not installed.',
152                         false,
153                         true,
154                         $install->getChecks());
155
156                 $this->mockFunctionL10TCalls();
157                 $this->setFunctions(['mb_strlen' => false]);
158                 $install = new Installer();
159                 $this->assertFalse($install->checkFunctions());
160                 $this->assertCheckExist(6,
161                         'mb_string PHP module',
162                         'Error: mb_string PHP module required but not installed.',
163                         false,
164                         true,
165                         $install->getChecks());
166
167                 $this->mockFunctionL10TCalls();
168                 $this->setFunctions(['iconv_strlen' => false]);
169                 $install = new Installer();
170                 $this->assertFalse($install->checkFunctions());
171                 $this->assertCheckExist(7,
172                         'iconv PHP module',
173                         'Error: iconv PHP module required but not installed.',
174                         false,
175                         true,
176                         $install->getChecks());
177
178                 $this->mockFunctionL10TCalls();
179                 $this->setFunctions(['posix_kill' => false]);
180                 $install = new Installer();
181                 $this->assertFalse($install->checkFunctions());
182                 $this->assertCheckExist(8,
183                         'POSIX PHP module',
184                         'Error: POSIX PHP module required but not installed.',
185                         false,
186                         true,
187                         $install->getChecks());
188
189                 $this->mockFunctionL10TCalls();
190                 $this->setFunctions(['json_encode' => false]);
191                 $install = new Installer();
192                 $this->assertFalse($install->checkFunctions());
193                 $this->assertCheckExist(9,
194                         'JSON PHP module',
195                         'Error: JSON PHP module required but not installed.',
196                         false,
197                         true,
198                         $install->getChecks());
199
200                 $this->mockFunctionL10TCalls();
201                 $this->setFunctions(['finfo_open' => false]);
202                 $install = new Installer();
203                 $this->assertFalse($install->checkFunctions());
204                 $this->assertCheckExist(10,
205                         'File Information PHP module',
206                         'Error: File Information PHP module required but not installed.',
207                         false,
208                         true,
209                         $install->getChecks());
210
211                 $this->mockFunctionL10TCalls();
212                 $this->setFunctions([
213                         'curl_init' => true,
214                         'imagecreatefromjpeg' => true,
215                         'openssl_public_encrypt' => true,
216                         'mb_strlen' => true,
217                         'iconv_strlen' => true,
218                         'posix_kill' => true,
219                         'json_encode' => true,
220                         'finfo_open' => true,
221                 ]);
222                 $install = new Installer();
223                 $this->assertTrue($install->checkFunctions());
224         }
225
226         /**
227          * @small
228          */
229         public function testCheckLocalIni()
230         {
231                 $this->mockL10nT();
232
233                 $this->assertTrue($this->root->hasChild('config/local.config.php'));
234
235                 $install = new Installer();
236                 $this->assertTrue($install->checkLocalIni());
237
238                 $this->delConfigFile('local.config.php');
239
240                 $this->assertFalse($this->root->hasChild('config/local.config.php'));
241
242                 $install = new Installer();
243                 $this->assertTrue($install->checkLocalIni());
244         }
245
246         /**
247          * @small
248          */
249         public function testCheckHtAccessFail()
250         {
251                 $this->mockL10nT();
252
253                 // Mocking the CURL Response
254                 $curlResult = \Mockery::mock(CurlResult::class);
255                 $curlResult
256                         ->shouldReceive('getReturnCode')
257                         ->andReturn('404');
258                 $curlResult
259                         ->shouldReceive('getRedirectUrl')
260                         ->andReturn('');
261                 $curlResult
262                         ->shouldReceive('getError')
263                         ->andReturn('test Error');
264
265                 // Mocking the CURL Request
266                 $networkMock = \Mockery::mock('alias:' . Network::class);
267                 $networkMock
268                         ->shouldReceive('fetchUrlFull')
269                         ->with('https://test/install/testrewrite')
270                         ->andReturn($curlResult);
271                 $networkMock
272                         ->shouldReceive('fetchUrlFull')
273                         ->with('http://test/install/testrewrite')
274                         ->andReturn($curlResult);
275
276                 // Mocking that we can use CURL
277                 $this->setFunctions(['curl_init' => true]);
278
279                 $install = new Installer();
280
281                 $this->assertFalse($install->checkHtAccess('https://test'));
282                 $this->assertSame('test Error', $install->getChecks()[0]['error_msg']['msg']);
283         }
284
285         /**
286          * @small
287          */
288         public function testCheckHtAccessWork()
289         {
290                 $this->mockL10nT();
291
292                 // Mocking the failed CURL Response
293                 $curlResultF = \Mockery::mock(CurlResult::class);
294                 $curlResultF
295                         ->shouldReceive('getReturnCode')
296                         ->andReturn('404');
297
298                 // Mocking the working CURL Response
299                 $curlResultW = \Mockery::mock(CurlResult::class);
300                 $curlResultW
301                         ->shouldReceive('getReturnCode')
302                         ->andReturn('204');
303
304                 // Mocking the CURL Request
305                 $networkMock = \Mockery::mock('alias:' . Network::class);
306                 $networkMock
307                         ->shouldReceive('fetchUrlFull')
308                         ->with('https://test/install/testrewrite')
309                         ->andReturn($curlResultF);
310                 $networkMock
311                         ->shouldReceive('fetchUrlFull')
312                         ->with('http://test/install/testrewrite')
313                         ->andReturn($curlResultW);
314
315                 // Mocking that we can use CURL
316                 $this->setFunctions(['curl_init' => true]);
317
318                 // needed because of "normalise_link"
319                 require_once __DIR__ . '/../../../include/text.php';
320
321                 $install = new Installer();
322
323                 $this->assertTrue($install->checkHtAccess('https://test'));
324         }
325
326         /**
327          * @small
328          */
329         public function testImagick()
330         {
331                 $this->mockL10nT();
332
333                 $imageMock = \Mockery::mock('alias:'. Image::class);
334                 $imageMock
335                         ->shouldReceive('supportedTypes')
336                         ->andReturn(['image/gif' => 'gif']);
337
338                 $this->setClasses(['Imagick' => true]);
339
340                 $install = new Installer();
341
342                 // even there is no supported type, Imagick should return true (because it is not required)
343                 $this->assertTrue($install->checkImagick());
344
345                 $this->assertCheckExist(1,
346                         L10n::t('ImageMagick supports GIF'),
347                         '',
348                         true,
349                         false,
350                         $install->getChecks());
351         }
352
353         /**
354          * @small
355          */
356         public function testImagickNotFound()
357         {
358                 $this->mockL10nT();
359
360                 $imageMock = \Mockery::mock('alias:' . Image::class);
361                 $imageMock
362                         ->shouldReceive('supportedTypes')
363                         ->andReturn([]);
364
365                 $this->setClasses(['Imagick' => true]);
366
367                 $install = new Installer();
368
369                 // even there is no supported type, Imagick should return true (because it is not required)
370                 $this->assertTrue($install->checkImagick());
371                 $this->assertCheckExist(1,
372                         L10n::t('ImageMagick supports GIF'),
373                         '',
374                         false,
375                         false,
376                         $install->getChecks());
377         }
378
379         public function testImagickNotInstalled()
380         {
381                 $this->setClasses(['Imagick' => false]);
382                 $this->mockL10nT('ImageMagick PHP extension is not installed');
383
384                 $install = new Installer();
385
386                 // even there is no supported type, Imagick should return true (because it is not required)
387                 $this->assertTrue($install->checkImagick());
388                 $this->assertCheckExist(0,
389                         'ImageMagick PHP extension is not installed',
390                         '',
391                         false,
392                         false,
393                         $install->getChecks());
394         }
395 }
396
397 /**
398  * A workaround to replace the PHP native function_exists with a mocked function
399  *
400  * @param string $function_name the Name of the function
401  *
402  * @return bool true or false
403  */
404 function function_exists($function_name)
405 {
406         global $phpMock;
407         if (isset($phpMock['function_exists'])) {
408                 $result = call_user_func_array($phpMock['function_exists'], func_get_args());
409                 if ($result !== '__phpunit_continue__') {
410                         return $result;
411                 }
412         }
413         return call_user_func_array('\function_exists', func_get_args());
414 }
415
416 function class_exists($class_name)
417 {
418         global $phpMock;
419         if (isset($phpMock['class_exists'])) {
420                 $result = call_user_func_array($phpMock['class_exists'], func_get_args());
421                 if ($result !== '__phpunit_continue__') {
422                         return $result;
423                 }
424         }
425         return call_user_func_array('\class_exists', func_get_args());
426 }