Completed
Pull Request — master (#4454)
by Lukas
17:18
created
lib/private/Installer.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -42,13 +42,11 @@
 block discarded – undo
42 42
 namespace OC;
43 43
 
44 44
 use Doctrine\DBAL\Exception\TableExistsException;
45
-use OC\App\AppManager;
46 45
 use OC\App\AppStore\Bundles\Bundle;
47 46
 use OC\App\AppStore\Fetcher\AppFetcher;
48 47
 use OC\App\CodeChecker\CodeChecker;
49 48
 use OC\App\CodeChecker\EmptyCheck;
50 49
 use OC\App\CodeChecker\PrivateCheck;
51
-use OC\Archive\Archive;
52 50
 use OC\Archive\TAR;
53 51
 use OC_App;
54 52
 use OC_DB;
Please login to merge, or discard this patch.
Indentation   +521 added lines, -521 removed lines patch added patch discarded remove patch
@@ -64,525 +64,525 @@
 block discarded – undo
64 64
  * This class provides the functionality needed to install, update and remove apps
65 65
  */
66 66
 class Installer {
67
-	/** @var AppFetcher */
68
-	private $appFetcher;
69
-	/** @var IAppManager */
70
-	private $appManager;
71
-	/** @var IClientService */
72
-	private $clientService;
73
-	/** @var ITempManager */
74
-	private $tempManager;
75
-	/** @var ILogger */
76
-	private $logger;
77
-	/** @var IConfig */
78
-	private $config;
79
-
80
-	/**
81
-	 * @param AppFetcher $appFetcher
82
-	 * @param IAppManager $appManager
83
-	 * @param IClientService $clientService
84
-	 * @param ITempManager $tempManager
85
-	 * @param ILogger $logger
86
-	 * @param IConfig $config
87
-	 */
88
-	public function __construct(AppFetcher $appFetcher,
89
-								IAppManager $appManager,
90
-								IClientService $clientService,
91
-								ITempManager $tempManager,
92
-								ILogger $logger,
93
-								IConfig $config) {
94
-		$this->appFetcher = $appFetcher;
95
-		$this->appManager = $appManager;
96
-		$this->clientService = $clientService;
97
-		$this->tempManager = $tempManager;
98
-		$this->logger = $logger;
99
-		$this->config = $config;
100
-	}
101
-
102
-	/**
103
-	 * Installs an app that is located in one of the app folders already
104
-	 *
105
-	 * @param string $appId App to install
106
-	 * @throws \Exception
107
-	 * @return integer
108
-	 */
109
-	public function installApp($appId) {
110
-		$app = \OC_App::findAppInDirectories($appId);
111
-		if($app === false) {
112
-			throw new \Exception('App not found in any app directory');
113
-		}
114
-
115
-		$basedir = $app['path'].'/'.$appId;
116
-		$info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
117
-
118
-		//install the database
119
-		if(is_file($basedir.'/appinfo/database.xml')) {
120
-			if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
121
-				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
122
-			} else {
123
-				OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
124
-			}
125
-		}
126
-
127
-		\OC_App::registerAutoloading($appId, $basedir);
128
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
129
-
130
-		//run appinfo/install.php
131
-		if((!isset($data['noinstall']) or $data['noinstall']==false)) {
132
-			self::includeAppScript($basedir . '/appinfo/install.php');
133
-		}
134
-
135
-		$appData = OC_App::getAppInfo($appId);
136
-		OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
137
-
138
-		//set the installed version
139
-		\OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
140
-		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
141
-
142
-		//set remote/public handlers
143
-		foreach($info['remote'] as $name=>$path) {
144
-			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
145
-		}
146
-		foreach($info['public'] as $name=>$path) {
147
-			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
148
-		}
149
-
150
-		OC_App::setAppTypes($info['id']);
151
-
152
-		return $info['id'];
153
-	}
154
-
155
-	/**
156
-	 * @brief checks whether or not an app is installed
157
-	 * @param string $app app
158
-	 * @returns bool
159
-	 *
160
-	 * Checks whether or not an app is installed, i.e. registered in apps table.
161
-	 */
162
-	public static function isInstalled( $app ) {
163
-		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
164
-	}
165
-
166
-	/**
167
-	 * Updates the specified app from the appstore
168
-	 *
169
-	 * @param string $appId
170
-	 * @return bool
171
-	 */
172
-	public function updateAppstoreApp($appId) {
173
-		if(self::isUpdateAvailable($appId, $this->appFetcher)) {
174
-			try {
175
-				$this->downloadApp($appId);
176
-			} catch (\Exception $e) {
177
-				$this->logger->error($e->getMessage(), ['app' => 'core']);
178
-				return false;
179
-			}
180
-			return OC_App::updateApp($appId);
181
-		}
182
-
183
-		return false;
184
-	}
185
-
186
-	/**
187
-	 * Downloads an app and puts it into the app directory
188
-	 *
189
-	 * @param string $appId
190
-	 *
191
-	 * @throws \Exception If the installation was not successful
192
-	 */
193
-	public function downloadApp($appId) {
194
-		$appId = strtolower($appId);
195
-
196
-		$apps = $this->appFetcher->get();
197
-		foreach($apps as $app) {
198
-			if($app['id'] === $appId) {
199
-				// Load the certificate
200
-				$certificate = new X509();
201
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
202
-				$loadedCertificate = $certificate->loadX509($app['certificate']);
203
-
204
-				// Verify if the certificate has been revoked
205
-				$crl = new X509();
206
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
207
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
208
-				if($crl->validateSignature() !== true) {
209
-					throw new \Exception('Could not validate CRL signature');
210
-				}
211
-				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
212
-				$revoked = $crl->getRevoked($csn);
213
-				if ($revoked !== false) {
214
-					throw new \Exception(
215
-						sprintf(
216
-							'Certificate "%s" has been revoked',
217
-							$csn
218
-						)
219
-					);
220
-				}
221
-
222
-				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
223
-				if($certificate->validateSignature() !== true) {
224
-					throw new \Exception(
225
-						sprintf(
226
-							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
227
-							$appId
228
-						)
229
-					);
230
-				}
231
-
232
-				// Verify if the certificate is issued for the requested app id
233
-				$certInfo = openssl_x509_parse($app['certificate']);
234
-				if(!isset($certInfo['subject']['CN'])) {
235
-					throw new \Exception(
236
-						sprintf(
237
-							'App with id %s has a cert with no CN',
238
-							$appId
239
-						)
240
-					);
241
-				}
242
-				if($certInfo['subject']['CN'] !== $appId) {
243
-					throw new \Exception(
244
-						sprintf(
245
-							'App with id %s has a cert issued to %s',
246
-							$appId,
247
-							$certInfo['subject']['CN']
248
-						)
249
-					);
250
-				}
251
-
252
-				// Download the release
253
-				$tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
254
-				$client = $this->clientService->newClient();
255
-				$client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
256
-
257
-				// Check if the signature actually matches the downloaded content
258
-				$certificate = openssl_get_publickey($app['certificate']);
259
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
260
-				openssl_free_key($certificate);
261
-
262
-				if($verified === true) {
263
-					// Seems to match, let's proceed
264
-					$extractDir = $this->tempManager->getTemporaryFolder();
265
-					$archive = new TAR($tempFile);
266
-
267
-					if($archive) {
268
-						$archive->extract($extractDir);
269
-						$allFiles = scandir($extractDir);
270
-						$folders = array_diff($allFiles, ['.', '..']);
271
-						$folders = array_values($folders);
272
-
273
-						if(count($folders) > 1) {
274
-							throw new \Exception(
275
-								sprintf(
276
-									'Extracted app %s has more than 1 folder',
277
-									$appId
278
-								)
279
-							);
280
-						}
281
-
282
-						// Check if appinfo/info.xml has the same app ID as well
283
-						$loadEntities = libxml_disable_entity_loader(false);
284
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
285
-						libxml_disable_entity_loader($loadEntities);
286
-						if((string)$xml->id !== $appId) {
287
-							throw new \Exception(
288
-								sprintf(
289
-									'App for id %s has a wrong app ID in info.xml: %s',
290
-									$appId,
291
-									(string)$xml->id
292
-								)
293
-							);
294
-						}
295
-
296
-						// Check if the version is lower than before
297
-						$currentVersion = OC_App::getAppVersion($appId);
298
-						$newVersion = (string)$xml->version;
299
-						if(version_compare($currentVersion, $newVersion) === 1) {
300
-							throw new \Exception(
301
-								sprintf(
302
-									'App for id %s has version %s and tried to update to lower version %s',
303
-									$appId,
304
-									$currentVersion,
305
-									$newVersion
306
-								)
307
-							);
308
-						}
309
-
310
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
311
-						// Remove old app with the ID if existent
312
-						OC_Helper::rmdirr($baseDir);
313
-						// Move to app folder
314
-						if(@mkdir($baseDir)) {
315
-							$extractDir .= '/' . $folders[0];
316
-							OC_Helper::copyr($extractDir, $baseDir);
317
-						}
318
-						OC_Helper::copyr($extractDir, $baseDir);
319
-						OC_Helper::rmdirr($extractDir);
320
-						return;
321
-					} else {
322
-						throw new \Exception(
323
-							sprintf(
324
-								'Could not extract app with ID %s to %s',
325
-								$appId,
326
-								$extractDir
327
-							)
328
-						);
329
-					}
330
-				} else {
331
-					// Signature does not match
332
-					throw new \Exception(
333
-						sprintf(
334
-							'App with id %s has invalid signature',
335
-							$appId
336
-						)
337
-					);
338
-				}
339
-			}
340
-		}
341
-
342
-		throw new \Exception(
343
-			sprintf(
344
-				'Could not download app %s',
345
-				$appId
346
-			)
347
-		);
348
-	}
349
-
350
-	/**
351
-	 * Check if an update for the app is available
352
-	 *
353
-	 * @param string $appId
354
-	 * @param AppFetcher $appFetcher
355
-	 * @return string|false false or the version number of the update
356
-	 */
357
-	public static function isUpdateAvailable($appId,
358
-									  AppFetcher $appFetcher) {
359
-		static $isInstanceReadyForUpdates = null;
360
-
361
-		if ($isInstanceReadyForUpdates === null) {
362
-			$installPath = OC_App::getInstallPath();
363
-			if ($installPath === false || $installPath === null) {
364
-				$isInstanceReadyForUpdates = false;
365
-			} else {
366
-				$isInstanceReadyForUpdates = true;
367
-			}
368
-		}
369
-
370
-		if ($isInstanceReadyForUpdates === false) {
371
-			return false;
372
-		}
373
-
374
-		$apps = $appFetcher->get();
375
-		foreach($apps as $app) {
376
-			if($app['id'] === $appId) {
377
-				$currentVersion = OC_App::getAppVersion($appId);
378
-				$newestVersion = $app['releases'][0]['version'];
379
-				if (version_compare($newestVersion, $currentVersion, '>')) {
380
-					return $newestVersion;
381
-				} else {
382
-					return false;
383
-				}
384
-			}
385
-		}
386
-
387
-		return false;
388
-	}
389
-
390
-	/**
391
-	 * Check if app is already downloaded
392
-	 * @param string $name name of the application to remove
393
-	 * @return boolean
394
-	 *
395
-	 * The function will check if the app is already downloaded in the apps repository
396
-	 */
397
-	public function isDownloaded($name) {
398
-		foreach(\OC::$APPSROOTS as $dir) {
399
-			$dirToTest  = $dir['path'];
400
-			$dirToTest .= '/';
401
-			$dirToTest .= $name;
402
-			$dirToTest .= '/';
403
-
404
-			if (is_dir($dirToTest)) {
405
-				return true;
406
-			}
407
-		}
408
-
409
-		return false;
410
-	}
411
-
412
-	/**
413
-	 * Removes an app
414
-	 * @param string $appId ID of the application to remove
415
-	 * @return boolean
416
-	 *
417
-	 *
418
-	 * This function works as follows
419
-	 *   -# call uninstall repair steps
420
-	 *   -# removing the files
421
-	 *
422
-	 * The function will not delete preferences, tables and the configuration,
423
-	 * this has to be done by the function oc_app_uninstall().
424
-	 */
425
-	public function removeApp($appId) {
426
-		if($this->isDownloaded( $appId )) {
427
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
428
-			OC_Helper::rmdirr($appDir);
429
-			return true;
430
-		}else{
431
-			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
432
-
433
-			return false;
434
-		}
435
-
436
-	}
437
-
438
-	/**
439
-	 * Installs the app within the bundle and marks the bundle as installed
440
-	 *
441
-	 * @param Bundle $bundle
442
-	 * @throws \Exception If app could not get installed
443
-	 */
444
-	public function installAppBundle(Bundle $bundle) {
445
-		$appIds = $bundle->getAppIdentifiers();
446
-		foreach($appIds as $appId) {
447
-			if(!$this->isDownloaded($appId)) {
448
-				$this->downloadApp($appId);
449
-			}
450
-			$this->installApp($appId);
451
-			$app = new OC_App();
452
-			$app->enable($appId);
453
-		}
454
-		$bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true);
455
-		$bundles[] = $bundle->getIdentifier();
456
-		$this->config->setAppValue('core', 'installed.bundles', json_encode($bundles));
457
-	}
458
-
459
-	/**
460
-	 * Installs shipped apps
461
-	 *
462
-	 * This function installs all apps found in the 'apps' directory that should be enabled by default;
463
-	 * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
464
-	 *                         working ownCloud at the end instead of an aborted update.
465
-	 * @return array Array of error messages (appid => Exception)
466
-	 */
467
-	public static function installShippedApps($softErrors = false) {
468
-		$errors = [];
469
-		foreach(\OC::$APPSROOTS as $app_dir) {
470
-			if($dir = opendir( $app_dir['path'] )) {
471
-				while( false !== ( $filename = readdir( $dir ))) {
472
-					if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
473
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
474
-							if(!Installer::isInstalled($filename)) {
475
-								$info=OC_App::getAppInfo($filename);
476
-								$enabled = isset($info['default_enable']);
477
-								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
478
-									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
479
-									if ($softErrors) {
480
-										try {
481
-											Installer::installShippedApp($filename);
482
-										} catch (HintException $e) {
483
-											if ($e->getPrevious() instanceof TableExistsException) {
484
-												$errors[$filename] = $e;
485
-												continue;
486
-											}
487
-											throw $e;
488
-										}
489
-									} else {
490
-										Installer::installShippedApp($filename);
491
-									}
492
-									\OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
493
-								}
494
-							}
495
-						}
496
-					}
497
-				}
498
-				closedir( $dir );
499
-			}
500
-		}
501
-
502
-		return $errors;
503
-	}
504
-
505
-	/**
506
-	 * install an app already placed in the app folder
507
-	 * @param string $app id of the app to install
508
-	 * @return integer
509
-	 */
510
-	public static function installShippedApp($app) {
511
-		//install the database
512
-		$appPath = OC_App::getAppPath($app);
513
-		if(is_file("$appPath/appinfo/database.xml")) {
514
-			try {
515
-				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
516
-			} catch (TableExistsException $e) {
517
-				throw new HintException(
518
-					'Failed to enable app ' . $app,
519
-					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
520
-					0, $e
521
-				);
522
-			}
523
-		}
524
-
525
-		//run appinfo/install.php
526
-		\OC_App::registerAutoloading($app, $appPath);
527
-		self::includeAppScript("$appPath/appinfo/install.php");
528
-
529
-		$info = OC_App::getAppInfo($app);
530
-		if (is_null($info)) {
531
-			return false;
532
-		}
533
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
534
-
535
-		OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
536
-
537
-		$config = \OC::$server->getConfig();
538
-
539
-		$config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
540
-		if (array_key_exists('ocsid', $info)) {
541
-			$config->setAppValue($app, 'ocsid', $info['ocsid']);
542
-		}
543
-
544
-		//set remote/public handlers
545
-		foreach($info['remote'] as $name=>$path) {
546
-			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
547
-		}
548
-		foreach($info['public'] as $name=>$path) {
549
-			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
550
-		}
551
-
552
-		OC_App::setAppTypes($info['id']);
553
-
554
-		if(isset($info['settings']) && is_array($info['settings'])) {
555
-			// requires that autoloading was registered for the app,
556
-			// as happens before running the install.php some lines above
557
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
558
-		}
559
-
560
-		return $info['id'];
561
-	}
562
-
563
-	/**
564
-	 * check the code of an app with some static code checks
565
-	 * @param string $folder the folder of the app to check
566
-	 * @return boolean true for app is o.k. and false for app is not o.k.
567
-	 */
568
-	public static function checkCode($folder) {
569
-		// is the code checker enabled?
570
-		if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
571
-			return true;
572
-		}
573
-
574
-		$codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
575
-		$errors = $codeChecker->analyseFolder(basename($folder), $folder);
576
-
577
-		return empty($errors);
578
-	}
579
-
580
-	/**
581
-	 * @param string $script
582
-	 */
583
-	private static function includeAppScript($script) {
584
-		if ( file_exists($script) ){
585
-			include $script;
586
-		}
587
-	}
67
+    /** @var AppFetcher */
68
+    private $appFetcher;
69
+    /** @var IAppManager */
70
+    private $appManager;
71
+    /** @var IClientService */
72
+    private $clientService;
73
+    /** @var ITempManager */
74
+    private $tempManager;
75
+    /** @var ILogger */
76
+    private $logger;
77
+    /** @var IConfig */
78
+    private $config;
79
+
80
+    /**
81
+     * @param AppFetcher $appFetcher
82
+     * @param IAppManager $appManager
83
+     * @param IClientService $clientService
84
+     * @param ITempManager $tempManager
85
+     * @param ILogger $logger
86
+     * @param IConfig $config
87
+     */
88
+    public function __construct(AppFetcher $appFetcher,
89
+                                IAppManager $appManager,
90
+                                IClientService $clientService,
91
+                                ITempManager $tempManager,
92
+                                ILogger $logger,
93
+                                IConfig $config) {
94
+        $this->appFetcher = $appFetcher;
95
+        $this->appManager = $appManager;
96
+        $this->clientService = $clientService;
97
+        $this->tempManager = $tempManager;
98
+        $this->logger = $logger;
99
+        $this->config = $config;
100
+    }
101
+
102
+    /**
103
+     * Installs an app that is located in one of the app folders already
104
+     *
105
+     * @param string $appId App to install
106
+     * @throws \Exception
107
+     * @return integer
108
+     */
109
+    public function installApp($appId) {
110
+        $app = \OC_App::findAppInDirectories($appId);
111
+        if($app === false) {
112
+            throw new \Exception('App not found in any app directory');
113
+        }
114
+
115
+        $basedir = $app['path'].'/'.$appId;
116
+        $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
117
+
118
+        //install the database
119
+        if(is_file($basedir.'/appinfo/database.xml')) {
120
+            if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
121
+                OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
122
+            } else {
123
+                OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
124
+            }
125
+        }
126
+
127
+        \OC_App::registerAutoloading($appId, $basedir);
128
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
129
+
130
+        //run appinfo/install.php
131
+        if((!isset($data['noinstall']) or $data['noinstall']==false)) {
132
+            self::includeAppScript($basedir . '/appinfo/install.php');
133
+        }
134
+
135
+        $appData = OC_App::getAppInfo($appId);
136
+        OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
137
+
138
+        //set the installed version
139
+        \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
140
+        \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
141
+
142
+        //set remote/public handlers
143
+        foreach($info['remote'] as $name=>$path) {
144
+            \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
145
+        }
146
+        foreach($info['public'] as $name=>$path) {
147
+            \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
148
+        }
149
+
150
+        OC_App::setAppTypes($info['id']);
151
+
152
+        return $info['id'];
153
+    }
154
+
155
+    /**
156
+     * @brief checks whether or not an app is installed
157
+     * @param string $app app
158
+     * @returns bool
159
+     *
160
+     * Checks whether or not an app is installed, i.e. registered in apps table.
161
+     */
162
+    public static function isInstalled( $app ) {
163
+        return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
164
+    }
165
+
166
+    /**
167
+     * Updates the specified app from the appstore
168
+     *
169
+     * @param string $appId
170
+     * @return bool
171
+     */
172
+    public function updateAppstoreApp($appId) {
173
+        if(self::isUpdateAvailable($appId, $this->appFetcher)) {
174
+            try {
175
+                $this->downloadApp($appId);
176
+            } catch (\Exception $e) {
177
+                $this->logger->error($e->getMessage(), ['app' => 'core']);
178
+                return false;
179
+            }
180
+            return OC_App::updateApp($appId);
181
+        }
182
+
183
+        return false;
184
+    }
185
+
186
+    /**
187
+     * Downloads an app and puts it into the app directory
188
+     *
189
+     * @param string $appId
190
+     *
191
+     * @throws \Exception If the installation was not successful
192
+     */
193
+    public function downloadApp($appId) {
194
+        $appId = strtolower($appId);
195
+
196
+        $apps = $this->appFetcher->get();
197
+        foreach($apps as $app) {
198
+            if($app['id'] === $appId) {
199
+                // Load the certificate
200
+                $certificate = new X509();
201
+                $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
202
+                $loadedCertificate = $certificate->loadX509($app['certificate']);
203
+
204
+                // Verify if the certificate has been revoked
205
+                $crl = new X509();
206
+                $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
207
+                $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
208
+                if($crl->validateSignature() !== true) {
209
+                    throw new \Exception('Could not validate CRL signature');
210
+                }
211
+                $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
212
+                $revoked = $crl->getRevoked($csn);
213
+                if ($revoked !== false) {
214
+                    throw new \Exception(
215
+                        sprintf(
216
+                            'Certificate "%s" has been revoked',
217
+                            $csn
218
+                        )
219
+                    );
220
+                }
221
+
222
+                // Verify if the certificate has been issued by the Nextcloud Code Authority CA
223
+                if($certificate->validateSignature() !== true) {
224
+                    throw new \Exception(
225
+                        sprintf(
226
+                            'App with id %s has a certificate not issued by a trusted Code Signing Authority',
227
+                            $appId
228
+                        )
229
+                    );
230
+                }
231
+
232
+                // Verify if the certificate is issued for the requested app id
233
+                $certInfo = openssl_x509_parse($app['certificate']);
234
+                if(!isset($certInfo['subject']['CN'])) {
235
+                    throw new \Exception(
236
+                        sprintf(
237
+                            'App with id %s has a cert with no CN',
238
+                            $appId
239
+                        )
240
+                    );
241
+                }
242
+                if($certInfo['subject']['CN'] !== $appId) {
243
+                    throw new \Exception(
244
+                        sprintf(
245
+                            'App with id %s has a cert issued to %s',
246
+                            $appId,
247
+                            $certInfo['subject']['CN']
248
+                        )
249
+                    );
250
+                }
251
+
252
+                // Download the release
253
+                $tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
254
+                $client = $this->clientService->newClient();
255
+                $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
256
+
257
+                // Check if the signature actually matches the downloaded content
258
+                $certificate = openssl_get_publickey($app['certificate']);
259
+                $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
260
+                openssl_free_key($certificate);
261
+
262
+                if($verified === true) {
263
+                    // Seems to match, let's proceed
264
+                    $extractDir = $this->tempManager->getTemporaryFolder();
265
+                    $archive = new TAR($tempFile);
266
+
267
+                    if($archive) {
268
+                        $archive->extract($extractDir);
269
+                        $allFiles = scandir($extractDir);
270
+                        $folders = array_diff($allFiles, ['.', '..']);
271
+                        $folders = array_values($folders);
272
+
273
+                        if(count($folders) > 1) {
274
+                            throw new \Exception(
275
+                                sprintf(
276
+                                    'Extracted app %s has more than 1 folder',
277
+                                    $appId
278
+                                )
279
+                            );
280
+                        }
281
+
282
+                        // Check if appinfo/info.xml has the same app ID as well
283
+                        $loadEntities = libxml_disable_entity_loader(false);
284
+                        $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
285
+                        libxml_disable_entity_loader($loadEntities);
286
+                        if((string)$xml->id !== $appId) {
287
+                            throw new \Exception(
288
+                                sprintf(
289
+                                    'App for id %s has a wrong app ID in info.xml: %s',
290
+                                    $appId,
291
+                                    (string)$xml->id
292
+                                )
293
+                            );
294
+                        }
295
+
296
+                        // Check if the version is lower than before
297
+                        $currentVersion = OC_App::getAppVersion($appId);
298
+                        $newVersion = (string)$xml->version;
299
+                        if(version_compare($currentVersion, $newVersion) === 1) {
300
+                            throw new \Exception(
301
+                                sprintf(
302
+                                    'App for id %s has version %s and tried to update to lower version %s',
303
+                                    $appId,
304
+                                    $currentVersion,
305
+                                    $newVersion
306
+                                )
307
+                            );
308
+                        }
309
+
310
+                        $baseDir = OC_App::getInstallPath() . '/' . $appId;
311
+                        // Remove old app with the ID if existent
312
+                        OC_Helper::rmdirr($baseDir);
313
+                        // Move to app folder
314
+                        if(@mkdir($baseDir)) {
315
+                            $extractDir .= '/' . $folders[0];
316
+                            OC_Helper::copyr($extractDir, $baseDir);
317
+                        }
318
+                        OC_Helper::copyr($extractDir, $baseDir);
319
+                        OC_Helper::rmdirr($extractDir);
320
+                        return;
321
+                    } else {
322
+                        throw new \Exception(
323
+                            sprintf(
324
+                                'Could not extract app with ID %s to %s',
325
+                                $appId,
326
+                                $extractDir
327
+                            )
328
+                        );
329
+                    }
330
+                } else {
331
+                    // Signature does not match
332
+                    throw new \Exception(
333
+                        sprintf(
334
+                            'App with id %s has invalid signature',
335
+                            $appId
336
+                        )
337
+                    );
338
+                }
339
+            }
340
+        }
341
+
342
+        throw new \Exception(
343
+            sprintf(
344
+                'Could not download app %s',
345
+                $appId
346
+            )
347
+        );
348
+    }
349
+
350
+    /**
351
+     * Check if an update for the app is available
352
+     *
353
+     * @param string $appId
354
+     * @param AppFetcher $appFetcher
355
+     * @return string|false false or the version number of the update
356
+     */
357
+    public static function isUpdateAvailable($appId,
358
+                                        AppFetcher $appFetcher) {
359
+        static $isInstanceReadyForUpdates = null;
360
+
361
+        if ($isInstanceReadyForUpdates === null) {
362
+            $installPath = OC_App::getInstallPath();
363
+            if ($installPath === false || $installPath === null) {
364
+                $isInstanceReadyForUpdates = false;
365
+            } else {
366
+                $isInstanceReadyForUpdates = true;
367
+            }
368
+        }
369
+
370
+        if ($isInstanceReadyForUpdates === false) {
371
+            return false;
372
+        }
373
+
374
+        $apps = $appFetcher->get();
375
+        foreach($apps as $app) {
376
+            if($app['id'] === $appId) {
377
+                $currentVersion = OC_App::getAppVersion($appId);
378
+                $newestVersion = $app['releases'][0]['version'];
379
+                if (version_compare($newestVersion, $currentVersion, '>')) {
380
+                    return $newestVersion;
381
+                } else {
382
+                    return false;
383
+                }
384
+            }
385
+        }
386
+
387
+        return false;
388
+    }
389
+
390
+    /**
391
+     * Check if app is already downloaded
392
+     * @param string $name name of the application to remove
393
+     * @return boolean
394
+     *
395
+     * The function will check if the app is already downloaded in the apps repository
396
+     */
397
+    public function isDownloaded($name) {
398
+        foreach(\OC::$APPSROOTS as $dir) {
399
+            $dirToTest  = $dir['path'];
400
+            $dirToTest .= '/';
401
+            $dirToTest .= $name;
402
+            $dirToTest .= '/';
403
+
404
+            if (is_dir($dirToTest)) {
405
+                return true;
406
+            }
407
+        }
408
+
409
+        return false;
410
+    }
411
+
412
+    /**
413
+     * Removes an app
414
+     * @param string $appId ID of the application to remove
415
+     * @return boolean
416
+     *
417
+     *
418
+     * This function works as follows
419
+     *   -# call uninstall repair steps
420
+     *   -# removing the files
421
+     *
422
+     * The function will not delete preferences, tables and the configuration,
423
+     * this has to be done by the function oc_app_uninstall().
424
+     */
425
+    public function removeApp($appId) {
426
+        if($this->isDownloaded( $appId )) {
427
+            $appDir = OC_App::getInstallPath() . '/' . $appId;
428
+            OC_Helper::rmdirr($appDir);
429
+            return true;
430
+        }else{
431
+            \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
432
+
433
+            return false;
434
+        }
435
+
436
+    }
437
+
438
+    /**
439
+     * Installs the app within the bundle and marks the bundle as installed
440
+     *
441
+     * @param Bundle $bundle
442
+     * @throws \Exception If app could not get installed
443
+     */
444
+    public function installAppBundle(Bundle $bundle) {
445
+        $appIds = $bundle->getAppIdentifiers();
446
+        foreach($appIds as $appId) {
447
+            if(!$this->isDownloaded($appId)) {
448
+                $this->downloadApp($appId);
449
+            }
450
+            $this->installApp($appId);
451
+            $app = new OC_App();
452
+            $app->enable($appId);
453
+        }
454
+        $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true);
455
+        $bundles[] = $bundle->getIdentifier();
456
+        $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles));
457
+    }
458
+
459
+    /**
460
+     * Installs shipped apps
461
+     *
462
+     * This function installs all apps found in the 'apps' directory that should be enabled by default;
463
+     * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
464
+     *                         working ownCloud at the end instead of an aborted update.
465
+     * @return array Array of error messages (appid => Exception)
466
+     */
467
+    public static function installShippedApps($softErrors = false) {
468
+        $errors = [];
469
+        foreach(\OC::$APPSROOTS as $app_dir) {
470
+            if($dir = opendir( $app_dir['path'] )) {
471
+                while( false !== ( $filename = readdir( $dir ))) {
472
+                    if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
473
+                        if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
474
+                            if(!Installer::isInstalled($filename)) {
475
+                                $info=OC_App::getAppInfo($filename);
476
+                                $enabled = isset($info['default_enable']);
477
+                                if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
478
+                                      && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
479
+                                    if ($softErrors) {
480
+                                        try {
481
+                                            Installer::installShippedApp($filename);
482
+                                        } catch (HintException $e) {
483
+                                            if ($e->getPrevious() instanceof TableExistsException) {
484
+                                                $errors[$filename] = $e;
485
+                                                continue;
486
+                                            }
487
+                                            throw $e;
488
+                                        }
489
+                                    } else {
490
+                                        Installer::installShippedApp($filename);
491
+                                    }
492
+                                    \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
493
+                                }
494
+                            }
495
+                        }
496
+                    }
497
+                }
498
+                closedir( $dir );
499
+            }
500
+        }
501
+
502
+        return $errors;
503
+    }
504
+
505
+    /**
506
+     * install an app already placed in the app folder
507
+     * @param string $app id of the app to install
508
+     * @return integer
509
+     */
510
+    public static function installShippedApp($app) {
511
+        //install the database
512
+        $appPath = OC_App::getAppPath($app);
513
+        if(is_file("$appPath/appinfo/database.xml")) {
514
+            try {
515
+                OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
516
+            } catch (TableExistsException $e) {
517
+                throw new HintException(
518
+                    'Failed to enable app ' . $app,
519
+                    'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
520
+                    0, $e
521
+                );
522
+            }
523
+        }
524
+
525
+        //run appinfo/install.php
526
+        \OC_App::registerAutoloading($app, $appPath);
527
+        self::includeAppScript("$appPath/appinfo/install.php");
528
+
529
+        $info = OC_App::getAppInfo($app);
530
+        if (is_null($info)) {
531
+            return false;
532
+        }
533
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
534
+
535
+        OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
536
+
537
+        $config = \OC::$server->getConfig();
538
+
539
+        $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
540
+        if (array_key_exists('ocsid', $info)) {
541
+            $config->setAppValue($app, 'ocsid', $info['ocsid']);
542
+        }
543
+
544
+        //set remote/public handlers
545
+        foreach($info['remote'] as $name=>$path) {
546
+            $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
547
+        }
548
+        foreach($info['public'] as $name=>$path) {
549
+            $config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
550
+        }
551
+
552
+        OC_App::setAppTypes($info['id']);
553
+
554
+        if(isset($info['settings']) && is_array($info['settings'])) {
555
+            // requires that autoloading was registered for the app,
556
+            // as happens before running the install.php some lines above
557
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
558
+        }
559
+
560
+        return $info['id'];
561
+    }
562
+
563
+    /**
564
+     * check the code of an app with some static code checks
565
+     * @param string $folder the folder of the app to check
566
+     * @return boolean true for app is o.k. and false for app is not o.k.
567
+     */
568
+    public static function checkCode($folder) {
569
+        // is the code checker enabled?
570
+        if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
571
+            return true;
572
+        }
573
+
574
+        $codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
575
+        $errors = $codeChecker->analyseFolder(basename($folder), $folder);
576
+
577
+        return empty($errors);
578
+    }
579
+
580
+    /**
581
+     * @param string $script
582
+     */
583
+    private static function includeAppScript($script) {
584
+        if ( file_exists($script) ){
585
+            include $script;
586
+        }
587
+    }
588 588
 }
Please login to merge, or discard this patch.
Spacing   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 	 */
109 109
 	public function installApp($appId) {
110 110
 		$app = \OC_App::findAppInDirectories($appId);
111
-		if($app === false) {
111
+		if ($app === false) {
112 112
 			throw new \Exception('App not found in any app directory');
113 113
 		}
114 114
 
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 		$info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
117 117
 
118 118
 		//install the database
119
-		if(is_file($basedir.'/appinfo/database.xml')) {
119
+		if (is_file($basedir.'/appinfo/database.xml')) {
120 120
 			if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
121 121
 				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
122 122
 			} else {
@@ -128,8 +128,8 @@  discard block
 block discarded – undo
128 128
 		\OC_App::setupBackgroundJobs($info['background-jobs']);
129 129
 
130 130
 		//run appinfo/install.php
131
-		if((!isset($data['noinstall']) or $data['noinstall']==false)) {
132
-			self::includeAppScript($basedir . '/appinfo/install.php');
131
+		if ((!isset($data['noinstall']) or $data['noinstall'] == false)) {
132
+			self::includeAppScript($basedir.'/appinfo/install.php');
133 133
 		}
134 134
 
135 135
 		$appData = OC_App::getAppInfo($appId);
@@ -140,10 +140,10 @@  discard block
 block discarded – undo
140 140
 		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
141 141
 
142 142
 		//set remote/public handlers
143
-		foreach($info['remote'] as $name=>$path) {
143
+		foreach ($info['remote'] as $name=>$path) {
144 144
 			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
145 145
 		}
146
-		foreach($info['public'] as $name=>$path) {
146
+		foreach ($info['public'] as $name=>$path) {
147 147
 			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
148 148
 		}
149 149
 
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
 	 *
160 160
 	 * Checks whether or not an app is installed, i.e. registered in apps table.
161 161
 	 */
162
-	public static function isInstalled( $app ) {
162
+	public static function isInstalled($app) {
163 163
 		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
164 164
 	}
165 165
 
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
 	 * @return bool
171 171
 	 */
172 172
 	public function updateAppstoreApp($appId) {
173
-		if(self::isUpdateAvailable($appId, $this->appFetcher)) {
173
+		if (self::isUpdateAvailable($appId, $this->appFetcher)) {
174 174
 			try {
175 175
 				$this->downloadApp($appId);
176 176
 			} catch (\Exception $e) {
@@ -194,18 +194,18 @@  discard block
 block discarded – undo
194 194
 		$appId = strtolower($appId);
195 195
 
196 196
 		$apps = $this->appFetcher->get();
197
-		foreach($apps as $app) {
198
-			if($app['id'] === $appId) {
197
+		foreach ($apps as $app) {
198
+			if ($app['id'] === $appId) {
199 199
 				// Load the certificate
200 200
 				$certificate = new X509();
201
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
201
+				$certificate->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
202 202
 				$loadedCertificate = $certificate->loadX509($app['certificate']);
203 203
 
204 204
 				// Verify if the certificate has been revoked
205 205
 				$crl = new X509();
206
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
207
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
208
-				if($crl->validateSignature() !== true) {
206
+				$crl->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
207
+				$crl->loadCRL(file_get_contents(__DIR__.'/../../resources/codesigning/root.crl'));
208
+				if ($crl->validateSignature() !== true) {
209 209
 					throw new \Exception('Could not validate CRL signature');
210 210
 				}
211 211
 				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 				}
221 221
 
222 222
 				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
223
-				if($certificate->validateSignature() !== true) {
223
+				if ($certificate->validateSignature() !== true) {
224 224
 					throw new \Exception(
225 225
 						sprintf(
226 226
 							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
 
232 232
 				// Verify if the certificate is issued for the requested app id
233 233
 				$certInfo = openssl_x509_parse($app['certificate']);
234
-				if(!isset($certInfo['subject']['CN'])) {
234
+				if (!isset($certInfo['subject']['CN'])) {
235 235
 					throw new \Exception(
236 236
 						sprintf(
237 237
 							'App with id %s has a cert with no CN',
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
 						)
240 240
 					);
241 241
 				}
242
-				if($certInfo['subject']['CN'] !== $appId) {
242
+				if ($certInfo['subject']['CN'] !== $appId) {
243 243
 					throw new \Exception(
244 244
 						sprintf(
245 245
 							'App with id %s has a cert issued to %s',
@@ -256,21 +256,21 @@  discard block
 block discarded – undo
256 256
 
257 257
 				// Check if the signature actually matches the downloaded content
258 258
 				$certificate = openssl_get_publickey($app['certificate']);
259
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
259
+				$verified = (bool) openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
260 260
 				openssl_free_key($certificate);
261 261
 
262
-				if($verified === true) {
262
+				if ($verified === true) {
263 263
 					// Seems to match, let's proceed
264 264
 					$extractDir = $this->tempManager->getTemporaryFolder();
265 265
 					$archive = new TAR($tempFile);
266 266
 
267
-					if($archive) {
267
+					if ($archive) {
268 268
 						$archive->extract($extractDir);
269 269
 						$allFiles = scandir($extractDir);
270 270
 						$folders = array_diff($allFiles, ['.', '..']);
271 271
 						$folders = array_values($folders);
272 272
 
273
-						if(count($folders) > 1) {
273
+						if (count($folders) > 1) {
274 274
 							throw new \Exception(
275 275
 								sprintf(
276 276
 									'Extracted app %s has more than 1 folder',
@@ -281,22 +281,22 @@  discard block
 block discarded – undo
281 281
 
282 282
 						// Check if appinfo/info.xml has the same app ID as well
283 283
 						$loadEntities = libxml_disable_entity_loader(false);
284
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
284
+						$xml = simplexml_load_file($extractDir.'/'.$folders[0].'/appinfo/info.xml');
285 285
 						libxml_disable_entity_loader($loadEntities);
286
-						if((string)$xml->id !== $appId) {
286
+						if ((string) $xml->id !== $appId) {
287 287
 							throw new \Exception(
288 288
 								sprintf(
289 289
 									'App for id %s has a wrong app ID in info.xml: %s',
290 290
 									$appId,
291
-									(string)$xml->id
291
+									(string) $xml->id
292 292
 								)
293 293
 							);
294 294
 						}
295 295
 
296 296
 						// Check if the version is lower than before
297 297
 						$currentVersion = OC_App::getAppVersion($appId);
298
-						$newVersion = (string)$xml->version;
299
-						if(version_compare($currentVersion, $newVersion) === 1) {
298
+						$newVersion = (string) $xml->version;
299
+						if (version_compare($currentVersion, $newVersion) === 1) {
300 300
 							throw new \Exception(
301 301
 								sprintf(
302 302
 									'App for id %s has version %s and tried to update to lower version %s',
@@ -307,12 +307,12 @@  discard block
 block discarded – undo
307 307
 							);
308 308
 						}
309 309
 
310
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
310
+						$baseDir = OC_App::getInstallPath().'/'.$appId;
311 311
 						// Remove old app with the ID if existent
312 312
 						OC_Helper::rmdirr($baseDir);
313 313
 						// Move to app folder
314
-						if(@mkdir($baseDir)) {
315
-							$extractDir .= '/' . $folders[0];
314
+						if (@mkdir($baseDir)) {
315
+							$extractDir .= '/'.$folders[0];
316 316
 							OC_Helper::copyr($extractDir, $baseDir);
317 317
 						}
318 318
 						OC_Helper::copyr($extractDir, $baseDir);
@@ -372,8 +372,8 @@  discard block
 block discarded – undo
372 372
 		}
373 373
 
374 374
 		$apps = $appFetcher->get();
375
-		foreach($apps as $app) {
376
-			if($app['id'] === $appId) {
375
+		foreach ($apps as $app) {
376
+			if ($app['id'] === $appId) {
377 377
 				$currentVersion = OC_App::getAppVersion($appId);
378 378
 				$newestVersion = $app['releases'][0]['version'];
379 379
 				if (version_compare($newestVersion, $currentVersion, '>')) {
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 	 * The function will check if the app is already downloaded in the apps repository
396 396
 	 */
397 397
 	public function isDownloaded($name) {
398
-		foreach(\OC::$APPSROOTS as $dir) {
398
+		foreach (\OC::$APPSROOTS as $dir) {
399 399
 			$dirToTest  = $dir['path'];
400 400
 			$dirToTest .= '/';
401 401
 			$dirToTest .= $name;
@@ -423,11 +423,11 @@  discard block
 block discarded – undo
423 423
 	 * this has to be done by the function oc_app_uninstall().
424 424
 	 */
425 425
 	public function removeApp($appId) {
426
-		if($this->isDownloaded( $appId )) {
427
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
426
+		if ($this->isDownloaded($appId)) {
427
+			$appDir = OC_App::getInstallPath().'/'.$appId;
428 428
 			OC_Helper::rmdirr($appDir);
429 429
 			return true;
430
-		}else{
430
+		} else {
431 431
 			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
432 432
 
433 433
 			return false;
@@ -443,8 +443,8 @@  discard block
 block discarded – undo
443 443
 	 */
444 444
 	public function installAppBundle(Bundle $bundle) {
445 445
 		$appIds = $bundle->getAppIdentifiers();
446
-		foreach($appIds as $appId) {
447
-			if(!$this->isDownloaded($appId)) {
446
+		foreach ($appIds as $appId) {
447
+			if (!$this->isDownloaded($appId)) {
448 448
 				$this->downloadApp($appId);
449 449
 			}
450 450
 			$this->installApp($appId);
@@ -466,13 +466,13 @@  discard block
 block discarded – undo
466 466
 	 */
467 467
 	public static function installShippedApps($softErrors = false) {
468 468
 		$errors = [];
469
-		foreach(\OC::$APPSROOTS as $app_dir) {
470
-			if($dir = opendir( $app_dir['path'] )) {
471
-				while( false !== ( $filename = readdir( $dir ))) {
472
-					if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
473
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
474
-							if(!Installer::isInstalled($filename)) {
475
-								$info=OC_App::getAppInfo($filename);
469
+		foreach (\OC::$APPSROOTS as $app_dir) {
470
+			if ($dir = opendir($app_dir['path'])) {
471
+				while (false !== ($filename = readdir($dir))) {
472
+					if (substr($filename, 0, 1) != '.' and is_dir($app_dir['path']."/$filename")) {
473
+						if (file_exists($app_dir['path']."/$filename/appinfo/info.xml")) {
474
+							if (!Installer::isInstalled($filename)) {
475
+								$info = OC_App::getAppInfo($filename);
476 476
 								$enabled = isset($info['default_enable']);
477 477
 								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
478 478
 									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
 						}
496 496
 					}
497 497
 				}
498
-				closedir( $dir );
498
+				closedir($dir);
499 499
 			}
500 500
 		}
501 501
 
@@ -510,12 +510,12 @@  discard block
 block discarded – undo
510 510
 	public static function installShippedApp($app) {
511 511
 		//install the database
512 512
 		$appPath = OC_App::getAppPath($app);
513
-		if(is_file("$appPath/appinfo/database.xml")) {
513
+		if (is_file("$appPath/appinfo/database.xml")) {
514 514
 			try {
515 515
 				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
516 516
 			} catch (TableExistsException $e) {
517 517
 				throw new HintException(
518
-					'Failed to enable app ' . $app,
518
+					'Failed to enable app '.$app,
519 519
 					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
520 520
 					0, $e
521 521
 				);
@@ -542,16 +542,16 @@  discard block
 block discarded – undo
542 542
 		}
543 543
 
544 544
 		//set remote/public handlers
545
-		foreach($info['remote'] as $name=>$path) {
545
+		foreach ($info['remote'] as $name=>$path) {
546 546
 			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
547 547
 		}
548
-		foreach($info['public'] as $name=>$path) {
548
+		foreach ($info['public'] as $name=>$path) {
549 549
 			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
550 550
 		}
551 551
 
552 552
 		OC_App::setAppTypes($info['id']);
553 553
 
554
-		if(isset($info['settings']) && is_array($info['settings'])) {
554
+		if (isset($info['settings']) && is_array($info['settings'])) {
555 555
 			// requires that autoloading was registered for the app,
556 556
 			// as happens before running the install.php some lines above
557 557
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -567,7 +567,7 @@  discard block
 block discarded – undo
567 567
 	 */
568 568
 	public static function checkCode($folder) {
569 569
 		// is the code checker enabled?
570
-		if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
570
+		if (!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
571 571
 			return true;
572 572
 		}
573 573
 
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
 	 * @param string $script
582 582
 	 */
583 583
 	private static function includeAppScript($script) {
584
-		if ( file_exists($script) ){
584
+		if (file_exists($script)) {
585 585
 			include $script;
586 586
 		}
587 587
 	}
Please login to merge, or discard this patch.
core/templates/installation.php 2 patches
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 script('core', [
3
-	'jquery-showpassword',
4
-	'installation'
3
+    'jquery-showpassword',
4
+    'installation'
5 5
 ]);
6 6
 
7 7
 /** @var array $_ */
@@ -34,9 +34,9 @@  discard block
 block discarded – undo
34 34
 		<legend><strong><?php p($l->t('Security warning'));?></strong></legend>
35 35
 		<p><?php p($l->t('Your data directory and files are probably accessible from the internet because the .htaccess file does not work.'));?><br>
36 36
 		<?php print_unescaped($l->t(
37
-			'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer">documentation</a>.',
38
-			link_to_docs('admin-install')
39
-		)); ?></p>
37
+            'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer">documentation</a>.',
38
+            link_to_docs('admin-install')
39
+        )); ?></p>
40 40
 	</fieldset>
41 41
 	<?php endif; ?>
42 42
 	<fieldset id="adminaccount">
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 	<?php if(!$_['dbIsSet'] OR count($_['errors']) > 0): ?>
102 102
 	<fieldset id='databaseBackend'>
103 103
 		<?php if($_['hasMySQL'] or $_['hasPostgreSQL'] or $_['hasOracle'])
104
-			$hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?>
104
+            $hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?>
105 105
 		<legend><?php p($l->t( 'Configure the database' )); ?></legend>
106 106
 		<div id="selectDbType">
107 107
 		<?php foreach($_['databases'] as $type => $label): ?>
Please login to merge, or discard this patch.
Spacing   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -14,12 +14,12 @@  discard block
 block discarded – undo
14 14
 <input type='hidden' id='hasOracle' value='<?php p($_['hasOracle']) ?>'>
15 15
 <form action="index.php" method="post">
16 16
 <input type="hidden" name="install" value="true">
17
-	<?php if(count($_['errors']) > 0): ?>
17
+	<?php if (count($_['errors']) > 0): ?>
18 18
 	<fieldset class="warning">
19
-		<legend><strong><?php p($l->t('Error'));?></strong></legend>
20
-		<?php foreach($_['errors'] as $err): ?>
19
+		<legend><strong><?php p($l->t('Error')); ?></strong></legend>
20
+		<?php foreach ($_['errors'] as $err): ?>
21 21
 		<p>
22
-			<?php if(is_array($err)):?>
22
+			<?php if (is_array($err)):?>
23 23
 				<?php print_unescaped($err['error']); ?>
24 24
 				<span class='hint'><?php print_unescaped($err['hint']); ?></span>
25 25
 			<?php else: ?>
@@ -29,10 +29,10 @@  discard block
 block discarded – undo
29 29
 		<?php endforeach; ?>
30 30
 	</fieldset>
31 31
 	<?php endif; ?>
32
-	<?php if(!$_['htaccessWorking']): ?>
32
+	<?php if (!$_['htaccessWorking']): ?>
33 33
 	<fieldset class="warning">
34
-		<legend><strong><?php p($l->t('Security warning'));?></strong></legend>
35
-		<p><?php p($l->t('Your data directory and files are probably accessible from the internet because the .htaccess file does not work.'));?><br>
34
+		<legend><strong><?php p($l->t('Security warning')); ?></strong></legend>
35
+		<p><?php p($l->t('Your data directory and files are probably accessible from the internet because the .htaccess file does not work.')); ?><br>
36 36
 		<?php print_unescaped($l->t(
37 37
 			'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer">documentation</a>.',
38 38
 			link_to_docs('admin-install')
@@ -40,20 +40,20 @@  discard block
 block discarded – undo
40 40
 	</fieldset>
41 41
 	<?php endif; ?>
42 42
 	<fieldset id="adminaccount">
43
-		<legend><?php print_unescaped($l->t( 'Create an <strong>admin account</strong>' )); ?></legend>
43
+		<legend><?php print_unescaped($l->t('Create an <strong>admin account</strong>')); ?></legend>
44 44
 		<p class="grouptop">
45 45
 			<input type="text" name="adminlogin" id="adminlogin"
46
-				placeholder="<?php p($l->t( 'Username' )); ?>"
46
+				placeholder="<?php p($l->t('Username')); ?>"
47 47
 				value="<?php p($_['adminlogin']); ?>"
48 48
 				autocomplete="off" autocapitalize="none" autocorrect="off" autofocus required>
49
-			<label for="adminlogin" class="infield"><?php p($l->t( 'Username' )); ?></label>
49
+			<label for="adminlogin" class="infield"><?php p($l->t('Username')); ?></label>
50 50
 		</p>
51 51
 		<p class="groupbottom">
52 52
 			<input type="password" name="adminpass" data-typetoggle="#show" id="adminpass"
53
-				placeholder="<?php p($l->t( 'Password' )); ?>"
53
+				placeholder="<?php p($l->t('Password')); ?>"
54 54
 				value="<?php p($_['adminpass']); ?>"
55 55
 				autocomplete="off" autocapitalize="none" autocorrect="off" required>
56
-			<label for="adminpass" class="infield"><?php p($l->t( 'Password' )); ?></label>
56
+			<label for="adminpass" class="infield"><?php p($l->t('Password')); ?></label>
57 57
 			<input type="checkbox" id="show" name="show">
58 58
 			<label for="show"></label>
59 59
 		</p>
@@ -61,9 +61,9 @@  discard block
 block discarded – undo
61 61
 
62 62
 
63 63
 	<fieldset>
64
-		<p class="info"><?php p($l->t( 'Install app bundles' )); ?></p>
64
+		<p class="info"><?php p($l->t('Install app bundles')); ?></p>
65 65
 
66
-		<?php foreach($bundles as $bundle): ?>
66
+		<?php foreach ($bundles as $bundle): ?>
67 67
 		<span class="app-bundle-toggler">
68 68
 			<p style="color: white">
69 69
 				<input type="checkbox" name="bundle[]" value="<?php p($bundle->getIdentifier()) ?>" id="<?php p($bundle->getIdentifier()) ?>" />
@@ -80,16 +80,16 @@  discard block
 block discarded – undo
80 80
 		<?php endforeach; ?>
81 81
 	</fieldset>
82 82
 
83
-	<?php if(!$_['directoryIsSet'] OR !$_['dbIsSet'] OR count($_['errors']) > 0): ?>
83
+	<?php if (!$_['directoryIsSet'] OR !$_['dbIsSet'] OR count($_['errors']) > 0): ?>
84 84
 	<fieldset id="advancedHeader">
85
-		<legend><a id="showAdvanced"><?php p($l->t( 'Storage & database' )); ?> <img src="<?php print_unescaped(image_path('', 'actions/caret.svg')); ?>" /></a></legend>
85
+		<legend><a id="showAdvanced"><?php p($l->t('Storage & database')); ?> <img src="<?php print_unescaped(image_path('', 'actions/caret.svg')); ?>" /></a></legend>
86 86
 	</fieldset>
87 87
 	<?php endif; ?>
88 88
 
89
-	<?php if(!$_['directoryIsSet'] OR count($_['errors']) > 0): ?>
89
+	<?php if (!$_['directoryIsSet'] OR count($_['errors']) > 0): ?>
90 90
 	<fieldset id="datadirField">
91 91
 		<div id="datadirContent">
92
-			<label for="directory"><?php p($l->t( 'Data folder' )); ?></label>
92
+			<label for="directory"><?php p($l->t('Data folder')); ?></label>
93 93
 			<input type="text" name="directory" id="directory"
94 94
 				placeholder="<?php p(OC::$SERVERROOT.'/data'); ?>"
95 95
 				value="<?php p($_['directory']); ?>"
@@ -98,19 +98,19 @@  discard block
 block discarded – undo
98 98
 	</fieldset>
99 99
 	<?php endif; ?>
100 100
 
101
-	<?php if(!$_['dbIsSet'] OR count($_['errors']) > 0): ?>
101
+	<?php if (!$_['dbIsSet'] OR count($_['errors']) > 0): ?>
102 102
 	<fieldset id='databaseBackend'>
103
-		<?php if($_['hasMySQL'] or $_['hasPostgreSQL'] or $_['hasOracle'])
104
-			$hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?>
105
-		<legend><?php p($l->t( 'Configure the database' )); ?></legend>
103
+		<?php if ($_['hasMySQL'] or $_['hasPostgreSQL'] or $_['hasOracle'])
104
+			$hasOtherDB = true; else $hasOtherDB = false; //other than SQLite ?>
105
+		<legend><?php p($l->t('Configure the database')); ?></legend>
106 106
 		<div id="selectDbType">
107
-		<?php foreach($_['databases'] as $type => $label): ?>
108
-		<?php if(count($_['databases']) === 1): ?>
107
+		<?php foreach ($_['databases'] as $type => $label): ?>
108
+		<?php if (count($_['databases']) === 1): ?>
109 109
 		<p class="info">
110
-			<?php p($l->t( 'Only %s is available.', array($label) )); ?>
111
-			<?php p($l->t( 'Install and activate additional PHP modules to choose other database types.' )); ?><br>
110
+			<?php p($l->t('Only %s is available.', array($label))); ?>
111
+			<?php p($l->t('Install and activate additional PHP modules to choose other database types.')); ?><br>
112 112
 			<a href="<?php print_unescaped(link_to_docs('admin-source_install')); ?>" target="_blank" rel="noreferrer">
113
-				<?php p($l->t( 'For more details check out the documentation.' )); ?> ↗</a>
113
+				<?php p($l->t('For more details check out the documentation.')); ?> ↗</a>
114 114
 		</p>
115 115
 		<input type="hidden" id="dbtype" name="dbtype" value="<?php p($type) ?>">
116 116
 		<?php else: ?>
@@ -122,75 +122,75 @@  discard block
 block discarded – undo
122 122
 		</div>
123 123
 	</fieldset>
124 124
 
125
-		<?php if($hasOtherDB): ?>
125
+		<?php if ($hasOtherDB): ?>
126 126
 		<fieldset id='databaseField'>
127 127
 		<div id="use_other_db">
128 128
 			<p class="grouptop">
129
-				<label for="dbuser" class="infield"><?php p($l->t( 'Database user' )); ?></label>
129
+				<label for="dbuser" class="infield"><?php p($l->t('Database user')); ?></label>
130 130
 				<input type="text" name="dbuser" id="dbuser"
131
-					placeholder="<?php p($l->t( 'Database user' )); ?>"
131
+					placeholder="<?php p($l->t('Database user')); ?>"
132 132
 					value="<?php p($_['dbuser']); ?>"
133 133
 					autocomplete="off" autocapitalize="none" autocorrect="off">
134 134
 			</p>
135 135
 			<p class="groupmiddle">
136 136
 				<input type="password" name="dbpass" id="dbpass" data-typetoggle="#dbpassword-toggle"
137
-					placeholder="<?php p($l->t( 'Database password' )); ?>"
137
+					placeholder="<?php p($l->t('Database password')); ?>"
138 138
 					value="<?php p($_['dbpass']); ?>"
139 139
 					autocomplete="off" autocapitalize="none" autocorrect="off">
140
-				<label for="dbpass" class="infield"><?php p($l->t( 'Database password' )); ?></label>
140
+				<label for="dbpass" class="infield"><?php p($l->t('Database password')); ?></label>
141 141
 				<input type="checkbox" id="dbpassword-toggle" name="dbpassword-toggle">
142 142
 				<label for="dbpassword-toggle"></label>
143 143
 			</p>
144 144
 			<p class="groupmiddle">
145
-				<label for="dbname" class="infield"><?php p($l->t( 'Database name' )); ?></label>
145
+				<label for="dbname" class="infield"><?php p($l->t('Database name')); ?></label>
146 146
 				<input type="text" name="dbname" id="dbname"
147
-					placeholder="<?php p($l->t( 'Database name' )); ?>"
147
+					placeholder="<?php p($l->t('Database name')); ?>"
148 148
 					value="<?php p($_['dbname']); ?>"
149 149
 					autocomplete="off" autocapitalize="none" autocorrect="off"
150 150
 					pattern="[0-9a-zA-Z$_-]+">
151 151
 			</p>
152
-			<?php if($_['hasOracle']): ?>
152
+			<?php if ($_['hasOracle']): ?>
153 153
 			<div id="use_oracle_db">
154 154
 				<p class="groupmiddle">
155
-					<label for="dbtablespace" class="infield"><?php p($l->t( 'Database tablespace' )); ?></label>
155
+					<label for="dbtablespace" class="infield"><?php p($l->t('Database tablespace')); ?></label>
156 156
 					<input type="text" name="dbtablespace" id="dbtablespace"
157
-						placeholder="<?php p($l->t( 'Database tablespace' )); ?>"
157
+						placeholder="<?php p($l->t('Database tablespace')); ?>"
158 158
 						value="<?php p($_['dbtablespace']); ?>"
159 159
 						autocomplete="off" autocapitalize="none" autocorrect="off">
160 160
 				</p>
161 161
 			</div>
162 162
 			<?php endif; ?>
163 163
 			<p class="groupbottom">
164
-				<label for="dbhost" class="infield"><?php p($l->t( 'Database host' )); ?></label>
164
+				<label for="dbhost" class="infield"><?php p($l->t('Database host')); ?></label>
165 165
 				<input type="text" name="dbhost" id="dbhost"
166
-					placeholder="<?php p($l->t( 'Database host' )); ?>"
166
+					placeholder="<?php p($l->t('Database host')); ?>"
167 167
 					value="<?php p($_['dbhost']); ?>"
168 168
 					autocomplete="off" autocapitalize="none" autocorrect="off">
169 169
 			</p>
170 170
 			<p class="info">
171
-				<?php p($l->t( 'Please specify the port number along with the host name (e.g., localhost:5432).' )); ?>
171
+				<?php p($l->t('Please specify the port number along with the host name (e.g., localhost:5432).')); ?>
172 172
 			</p>
173 173
 		</div>
174 174
 		</fieldset>
175 175
 		<?php endif; ?>
176 176
 	<?php endif; ?>
177 177
 
178
-	<?php if(!$_['dbIsSet'] OR count($_['errors']) > 0): ?>
178
+	<?php if (!$_['dbIsSet'] OR count($_['errors']) > 0): ?>
179 179
 		<fieldset id="sqliteInformation" class="warning">
180
-			<legend><?php p($l->t('Performance warning'));?></legend>
181
-			<p><?php p($l->t('SQLite will be used as database.'));?></p>
182
-			<p><?php p($l->t('For larger installations we recommend to choose a different database backend.'));?></p>
180
+			<legend><?php p($l->t('Performance warning')); ?></legend>
181
+			<p><?php p($l->t('SQLite will be used as database.')); ?></p>
182
+			<p><?php p($l->t('For larger installations we recommend to choose a different database backend.')); ?></p>
183 183
 			<p><?php p($l->t('Especially when using the desktop client for file syncing the use of SQLite is discouraged.')); ?></p>
184 184
 		</fieldset>
185 185
 	<?php endif ?>
186 186
 
187 187
 	<div class="icon-loading-dark float-spinner">&nbsp;</div>
188 188
 
189
-	<div class="buttons"><input type="submit" class="primary" value="<?php p($l->t( 'Finish setup' )); ?>" data-finishing="<?php p($l->t( 'Finishing …' )); ?>"></div>
189
+	<div class="buttons"><input type="submit" class="primary" value="<?php p($l->t('Finish setup')); ?>" data-finishing="<?php p($l->t('Finishing …')); ?>"></div>
190 190
 
191 191
 	<p class="info">
192 192
 		<span class="icon-info-white"></span>
193
-		<?php p($l->t('Need help?'));?>
194
-		<a target="_blank" rel="noreferrer" href="<?php p(link_to_docs('admin-install')); ?>"><?php p($l->t('See the documentation'));?> ↗</a>
193
+		<?php p($l->t('Need help?')); ?>
194
+		<a target="_blank" rel="noreferrer" href="<?php p(link_to_docs('admin-install')); ?>"><?php p($l->t('See the documentation')); ?> ↗</a>
195 195
 	</p>
196 196
 </form>
Please login to merge, or discard this patch.
core/Controller/SetupController.php 1 patch
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -32,104 +32,104 @@
 block discarded – undo
32 32
 use OC\Setup;
33 33
 
34 34
 class SetupController {
35
-	/** @var Setup */
36
-	protected $setupHelper;
37
-	/** @var string */
38
-	private $autoConfigFile;
39
-	/** @var BundleFetcher */
40
-	private $bundleFetcher;
41
-
42
-	/**
43
-	 * @param Setup $setupHelper
44
-	 * @param BundleFetcher $bundleFetcher
45
-	 */
46
-	public function __construct(Setup $setupHelper,
47
-						 BundleFetcher $bundleFetcher) {
48
-		$this->autoConfigFile = \OC::$configDir.'autoconfig.php';
49
-		$this->setupHelper = $setupHelper;
50
-		$this->bundleFetcher = $bundleFetcher;
51
-	}
52
-
53
-	/**
54
-	 * @param $post
55
-	 */
56
-	public function run($post) {
57
-		// Check for autosetup:
58
-		$post = $this->loadAutoConfig($post);
59
-		$opts = $this->setupHelper->getSystemInfo();
60
-
61
-		// convert 'abcpassword' to 'abcpass'
62
-		if (isset($post['adminpassword'])) {
63
-			$post['adminpass'] = $post['adminpassword'];
64
-		}
65
-		if (isset($post['dbpassword'])) {
66
-			$post['dbpass'] = $post['dbpassword'];
67
-		}
68
-
69
-		if(isset($post['install']) AND $post['install']=='true') {
70
-			// We have to launch the installation process :
71
-			$e = $this->setupHelper->install($post);
72
-			$errors = array('errors' => $e);
73
-
74
-			if(count($e) > 0) {
75
-				$options = array_merge($opts, $post, $errors);
76
-				$this->display($options);
77
-			} else {
78
-				$this->finishSetup();
79
-			}
80
-		} else {
81
-			$options = array_merge($opts, $post);
82
-			$this->display($options);
83
-		}
84
-	}
85
-
86
-	public function display($post) {
87
-		$defaults = array(
88
-			'adminlogin' => '',
89
-			'adminpass' => '',
90
-			'dbuser' => '',
91
-			'dbpass' => '',
92
-			'dbname' => '',
93
-			'dbtablespace' => '',
94
-			'dbhost' => 'localhost',
95
-			'dbtype' => '',
96
-			'bundles' => $this->bundleFetcher->getBundles(),
97
-		);
98
-
99
-		$parameters = array_merge($defaults, $post);
100
-
101
-		\OC_Util::addVendorScript('strengthify/jquery.strengthify');
102
-		\OC_Util::addVendorStyle('strengthify/strengthify');
103
-		\OC_Util::addScript('setup');
104
-		\OC_Template::printGuestPage('', 'installation', $parameters);
105
-	}
106
-
107
-	public function finishSetup() {
108
-		if( file_exists( $this->autoConfigFile )) {
109
-			unlink($this->autoConfigFile);
110
-		}
111
-		\OC::$server->getIntegrityCodeChecker()->runInstanceVerification();
112
-		\OC_Util::redirectToDefaultPage();
113
-	}
114
-
115
-	public function loadAutoConfig($post) {
116
-		if( file_exists($this->autoConfigFile)) {
117
-			\OCP\Util::writeLog('core', 'Autoconfig file found, setting up ownCloud…', \OCP\Util::INFO);
118
-			$AUTOCONFIG = array();
119
-			include $this->autoConfigFile;
120
-			$post = array_merge ($post, $AUTOCONFIG);
121
-		}
122
-
123
-		$dbIsSet = isset($post['dbtype']);
124
-		$directoryIsSet = isset($post['directory']);
125
-		$adminAccountIsSet = isset($post['adminlogin']);
126
-
127
-		if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) {
128
-			$post['install'] = 'true';
129
-		}
130
-		$post['dbIsSet'] = $dbIsSet;
131
-		$post['directoryIsSet'] = $directoryIsSet;
132
-
133
-		return $post;
134
-	}
35
+    /** @var Setup */
36
+    protected $setupHelper;
37
+    /** @var string */
38
+    private $autoConfigFile;
39
+    /** @var BundleFetcher */
40
+    private $bundleFetcher;
41
+
42
+    /**
43
+     * @param Setup $setupHelper
44
+     * @param BundleFetcher $bundleFetcher
45
+     */
46
+    public function __construct(Setup $setupHelper,
47
+                            BundleFetcher $bundleFetcher) {
48
+        $this->autoConfigFile = \OC::$configDir.'autoconfig.php';
49
+        $this->setupHelper = $setupHelper;
50
+        $this->bundleFetcher = $bundleFetcher;
51
+    }
52
+
53
+    /**
54
+     * @param $post
55
+     */
56
+    public function run($post) {
57
+        // Check for autosetup:
58
+        $post = $this->loadAutoConfig($post);
59
+        $opts = $this->setupHelper->getSystemInfo();
60
+
61
+        // convert 'abcpassword' to 'abcpass'
62
+        if (isset($post['adminpassword'])) {
63
+            $post['adminpass'] = $post['adminpassword'];
64
+        }
65
+        if (isset($post['dbpassword'])) {
66
+            $post['dbpass'] = $post['dbpassword'];
67
+        }
68
+
69
+        if(isset($post['install']) AND $post['install']=='true') {
70
+            // We have to launch the installation process :
71
+            $e = $this->setupHelper->install($post);
72
+            $errors = array('errors' => $e);
73
+
74
+            if(count($e) > 0) {
75
+                $options = array_merge($opts, $post, $errors);
76
+                $this->display($options);
77
+            } else {
78
+                $this->finishSetup();
79
+            }
80
+        } else {
81
+            $options = array_merge($opts, $post);
82
+            $this->display($options);
83
+        }
84
+    }
85
+
86
+    public function display($post) {
87
+        $defaults = array(
88
+            'adminlogin' => '',
89
+            'adminpass' => '',
90
+            'dbuser' => '',
91
+            'dbpass' => '',
92
+            'dbname' => '',
93
+            'dbtablespace' => '',
94
+            'dbhost' => 'localhost',
95
+            'dbtype' => '',
96
+            'bundles' => $this->bundleFetcher->getBundles(),
97
+        );
98
+
99
+        $parameters = array_merge($defaults, $post);
100
+
101
+        \OC_Util::addVendorScript('strengthify/jquery.strengthify');
102
+        \OC_Util::addVendorStyle('strengthify/strengthify');
103
+        \OC_Util::addScript('setup');
104
+        \OC_Template::printGuestPage('', 'installation', $parameters);
105
+    }
106
+
107
+    public function finishSetup() {
108
+        if( file_exists( $this->autoConfigFile )) {
109
+            unlink($this->autoConfigFile);
110
+        }
111
+        \OC::$server->getIntegrityCodeChecker()->runInstanceVerification();
112
+        \OC_Util::redirectToDefaultPage();
113
+    }
114
+
115
+    public function loadAutoConfig($post) {
116
+        if( file_exists($this->autoConfigFile)) {
117
+            \OCP\Util::writeLog('core', 'Autoconfig file found, setting up ownCloud…', \OCP\Util::INFO);
118
+            $AUTOCONFIG = array();
119
+            include $this->autoConfigFile;
120
+            $post = array_merge ($post, $AUTOCONFIG);
121
+        }
122
+
123
+        $dbIsSet = isset($post['dbtype']);
124
+        $directoryIsSet = isset($post['directory']);
125
+        $adminAccountIsSet = isset($post['adminlogin']);
126
+
127
+        if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) {
128
+            $post['install'] = 'true';
129
+        }
130
+        $post['dbIsSet'] = $dbIsSet;
131
+        $post['directoryIsSet'] = $directoryIsSet;
132
+
133
+        return $post;
134
+    }
135 135
 }
Please login to merge, or discard this patch.
settings/ajax/updateapp.php 1 patch
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -28,10 +28,10 @@  discard block
 block discarded – undo
28 28
 OCP\JSON::callCheck();
29 29
 
30 30
 if (!array_key_exists('appid', $_POST)) {
31
-	OCP\JSON::error(array(
32
-		'message' => 'No AppId given!'
33
-	));
34
-	return;
31
+    OCP\JSON::error(array(
32
+        'message' => 'No AppId given!'
33
+    ));
34
+    return;
35 35
 }
36 36
 
37 37
 $appId = (string)$_POST['appid'];
@@ -40,25 +40,25 @@  discard block
 block discarded – undo
40 40
 $config = \OC::$server->getConfig();
41 41
 $config->setSystemValue('maintenance', true);
42 42
 try {
43
-	$installer = new \OC\Installer(
44
-		\OC::$server->getAppFetcher(),
45
-		\OC::$server->getAppManager(),
46
-		\OC::$server->getHTTPClientService(),
47
-		\OC::$server->getTempManager(),
48
-		\OC::$server->getLogger(),
49
-		\OC::$server->getConfig()
50
-	);
51
-	$result = $installer->updateAppstoreApp($appId);
52
-	$config->setSystemValue('maintenance', false);
43
+    $installer = new \OC\Installer(
44
+        \OC::$server->getAppFetcher(),
45
+        \OC::$server->getAppManager(),
46
+        \OC::$server->getHTTPClientService(),
47
+        \OC::$server->getTempManager(),
48
+        \OC::$server->getLogger(),
49
+        \OC::$server->getConfig()
50
+    );
51
+    $result = $installer->updateAppstoreApp($appId);
52
+    $config->setSystemValue('maintenance', false);
53 53
 } catch(Exception $ex) {
54
-	$config->setSystemValue('maintenance', false);
55
-	OC_JSON::error(array("data" => array( "message" => $ex->getMessage() )));
56
-	return;
54
+    $config->setSystemValue('maintenance', false);
55
+    OC_JSON::error(array("data" => array( "message" => $ex->getMessage() )));
56
+    return;
57 57
 }
58 58
 
59 59
 if($result !== false) {
60
-	OC_JSON::success(array('data' => array('appid' => $appId)));
60
+    OC_JSON::success(array('data' => array('appid' => $appId)));
61 61
 } else {
62
-	$l = \OC::$server->getL10N('settings');
63
-	OC_JSON::error(array("data" => array( "message" => $l->t("Couldn't update app.") )));
62
+    $l = \OC::$server->getL10N('settings');
63
+    OC_JSON::error(array("data" => array( "message" => $l->t("Couldn't update app.") )));
64 64
 }
Please login to merge, or discard this patch.
lib/private/legacy/app.php 1 patch
Indentation   +1280 added lines, -1280 removed lines patch added patch discarded remove patch
@@ -61,1284 +61,1284 @@
 block discarded – undo
61 61
  * upgrading and removing apps.
62 62
  */
63 63
 class OC_App {
64
-	static private $appVersion = [];
65
-	static private $adminForms = array();
66
-	static private $personalForms = array();
67
-	static private $appInfo = array();
68
-	static private $appTypes = array();
69
-	static private $loadedApps = array();
70
-	static private $altLogin = array();
71
-	static private $alreadyRegistered = [];
72
-	const officialApp = 200;
73
-
74
-	/**
75
-	 * clean the appId
76
-	 *
77
-	 * @param string|boolean $app AppId that needs to be cleaned
78
-	 * @return string
79
-	 */
80
-	public static function cleanAppId($app) {
81
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
-	}
83
-
84
-	/**
85
-	 * Check if an app is loaded
86
-	 *
87
-	 * @param string $app
88
-	 * @return bool
89
-	 */
90
-	public static function isAppLoaded($app) {
91
-		return in_array($app, self::$loadedApps, true);
92
-	}
93
-
94
-	/**
95
-	 * loads all apps
96
-	 *
97
-	 * @param string[] | string | null $types
98
-	 * @return bool
99
-	 *
100
-	 * This function walks through the ownCloud directory and loads all apps
101
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
102
-	 * exists.
103
-	 *
104
-	 * if $types is set, only apps of those types will be loaded
105
-	 */
106
-	public static function loadApps($types = null) {
107
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
-			return false;
109
-		}
110
-		// Load the enabled apps here
111
-		$apps = self::getEnabledApps();
112
-
113
-		// Add each apps' folder as allowed class path
114
-		foreach($apps as $app) {
115
-			$path = self::getAppPath($app);
116
-			if($path !== false) {
117
-				self::registerAutoloading($app, $path);
118
-			}
119
-		}
120
-
121
-		// prevent app.php from printing output
122
-		ob_start();
123
-		foreach ($apps as $app) {
124
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
-				self::loadApp($app);
126
-			}
127
-		}
128
-		ob_end_clean();
129
-
130
-		return true;
131
-	}
132
-
133
-	/**
134
-	 * load a single app
135
-	 *
136
-	 * @param string $app
137
-	 */
138
-	public static function loadApp($app) {
139
-		self::$loadedApps[] = $app;
140
-		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
142
-			return;
143
-		}
144
-
145
-		// in case someone calls loadApp() directly
146
-		self::registerAutoloading($app, $appPath);
147
-
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
-			self::requireAppFile($app);
151
-			if (self::isType($app, array('authentication'))) {
152
-				// since authentication apps affect the "is app enabled for group" check,
153
-				// the enabled apps cache needs to be cleared to make sure that the
154
-				// next time getEnableApps() is called it will also include apps that were
155
-				// enabled for groups
156
-				self::$enabledAppsCache = array();
157
-			}
158
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
159
-		}
160
-
161
-		$info = self::getAppInfo($app);
162
-		if (!empty($info['activity']['filters'])) {
163
-			foreach ($info['activity']['filters'] as $filter) {
164
-				\OC::$server->getActivityManager()->registerFilter($filter);
165
-			}
166
-		}
167
-		if (!empty($info['activity']['settings'])) {
168
-			foreach ($info['activity']['settings'] as $setting) {
169
-				\OC::$server->getActivityManager()->registerSetting($setting);
170
-			}
171
-		}
172
-		if (!empty($info['activity']['providers'])) {
173
-			foreach ($info['activity']['providers'] as $provider) {
174
-				\OC::$server->getActivityManager()->registerProvider($provider);
175
-			}
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * @internal
181
-	 * @param string $app
182
-	 * @param string $path
183
-	 */
184
-	public static function registerAutoloading($app, $path) {
185
-		$key = $app . '-' . $path;
186
-		if(isset(self::$alreadyRegistered[$key])) {
187
-			return;
188
-		}
189
-		self::$alreadyRegistered[$key] = true;
190
-		// Register on PSR-4 composer autoloader
191
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
-		\OC::$server->registerNamespace($app, $appNamespace);
193
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
194
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
195
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
196
-		}
197
-
198
-		// Register on legacy autoloader
199
-		\OC::$loader->addValidRoot($path);
200
-	}
201
-
202
-	/**
203
-	 * Load app.php from the given app
204
-	 *
205
-	 * @param string $app app name
206
-	 */
207
-	private static function requireAppFile($app) {
208
-		try {
209
-			// encapsulated here to avoid variable scope conflicts
210
-			require_once $app . '/appinfo/app.php';
211
-		} catch (Error $ex) {
212
-			\OC::$server->getLogger()->logException($ex);
213
-			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
214
-			if (!in_array($app, $blacklist)) {
215
-				self::disable($app);
216
-			}
217
-		}
218
-	}
219
-
220
-	/**
221
-	 * check if an app is of a specific type
222
-	 *
223
-	 * @param string $app
224
-	 * @param string|array $types
225
-	 * @return bool
226
-	 */
227
-	public static function isType($app, $types) {
228
-		if (is_string($types)) {
229
-			$types = array($types);
230
-		}
231
-		$appTypes = self::getAppTypes($app);
232
-		foreach ($types as $type) {
233
-			if (array_search($type, $appTypes) !== false) {
234
-				return true;
235
-			}
236
-		}
237
-		return false;
238
-	}
239
-
240
-	/**
241
-	 * get the types of an app
242
-	 *
243
-	 * @param string $app
244
-	 * @return array
245
-	 */
246
-	private static function getAppTypes($app) {
247
-		//load the cache
248
-		if (count(self::$appTypes) == 0) {
249
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
250
-		}
251
-
252
-		if (isset(self::$appTypes[$app])) {
253
-			return explode(',', self::$appTypes[$app]);
254
-		} else {
255
-			return array();
256
-		}
257
-	}
258
-
259
-	/**
260
-	 * read app types from info.xml and cache them in the database
261
-	 */
262
-	public static function setAppTypes($app) {
263
-		$appData = self::getAppInfo($app);
264
-		if(!is_array($appData)) {
265
-			return;
266
-		}
267
-
268
-		if (isset($appData['types'])) {
269
-			$appTypes = implode(',', $appData['types']);
270
-		} else {
271
-			$appTypes = '';
272
-			$appData['types'] = [];
273
-		}
274
-
275
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
276
-
277
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
278
-			$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
279
-			if ($enabled !== 'yes' && $enabled !== 'no') {
280
-				\OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
281
-			}
282
-		}
283
-	}
284
-
285
-	/**
286
-	 * check if app is shipped
287
-	 *
288
-	 * @param string $appId the id of the app to check
289
-	 * @return bool
290
-	 *
291
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
292
-	 */
293
-	public static function isShipped($appId) {
294
-		return \OC::$server->getAppManager()->isShipped($appId);
295
-	}
296
-
297
-	/**
298
-	 * get all enabled apps
299
-	 */
300
-	protected static $enabledAppsCache = array();
301
-
302
-	/**
303
-	 * Returns apps enabled for the current user.
304
-	 *
305
-	 * @param bool $forceRefresh whether to refresh the cache
306
-	 * @param bool $all whether to return apps for all users, not only the
307
-	 * currently logged in one
308
-	 * @return string[]
309
-	 */
310
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
311
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
312
-			return array();
313
-		}
314
-		// in incognito mode or when logged out, $user will be false,
315
-		// which is also the case during an upgrade
316
-		$appManager = \OC::$server->getAppManager();
317
-		if ($all) {
318
-			$user = null;
319
-		} else {
320
-			$user = \OC::$server->getUserSession()->getUser();
321
-		}
322
-
323
-		if (is_null($user)) {
324
-			$apps = $appManager->getInstalledApps();
325
-		} else {
326
-			$apps = $appManager->getEnabledAppsForUser($user);
327
-		}
328
-		$apps = array_filter($apps, function ($app) {
329
-			return $app !== 'files';//we add this manually
330
-		});
331
-		sort($apps);
332
-		array_unshift($apps, 'files');
333
-		return $apps;
334
-	}
335
-
336
-	/**
337
-	 * checks whether or not an app is enabled
338
-	 *
339
-	 * @param string $app app
340
-	 * @return bool
341
-	 *
342
-	 * This function checks whether or not an app is enabled.
343
-	 */
344
-	public static function isEnabled($app) {
345
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
346
-	}
347
-
348
-	/**
349
-	 * enables an app
350
-	 *
351
-	 * @param string $appId
352
-	 * @param array $groups (optional) when set, only these groups will have access to the app
353
-	 * @throws \Exception
354
-	 * @return void
355
-	 *
356
-	 * This function set an app as enabled in appconfig.
357
-	 */
358
-	public function enable($appId,
359
-						   $groups = null) {
360
-		self::$enabledAppsCache = []; // flush
361
-		$l = \OC::$server->getL10N('core');
362
-		$config = \OC::$server->getConfig();
363
-
364
-		// Check if app is already downloaded
365
-		$installer = new Installer(
366
-			\OC::$server->getAppFetcher(),
367
-			\OC::$server->getAppManager(),
368
-			\OC::$server->getHTTPClientService(),
369
-			\OC::$server->getTempManager(),
370
-			\OC::$server->getLogger(),
371
-			\OC::$server->getConfig()
372
-		);
373
-		$isDownloaded = $installer->isDownloaded($appId);
374
-
375
-		if(!$isDownloaded) {
376
-			$installer->downloadApp($appId);
377
-		}
378
-
379
-		if (!Installer::isInstalled($appId)) {
380
-			$appId = self::installApp(
381
-				$appId,
382
-				$config,
383
-				$l
384
-			);
385
-			$appPath = self::getAppPath($appId);
386
-			self::registerAutoloading($appId, $appPath);
387
-			$installer->installApp($appId);
388
-		} else {
389
-			// check for required dependencies
390
-			$info = self::getAppInfo($appId);
391
-			self::checkAppDependencies($config, $l, $info);
392
-			$appPath = self::getAppPath($appId);
393
-			self::registerAutoloading($appId, $appPath);
394
-			$installer->installApp($appId);
395
-		}
396
-
397
-		$appManager = \OC::$server->getAppManager();
398
-		if (!is_null($groups)) {
399
-			$groupManager = \OC::$server->getGroupManager();
400
-			$groupsList = [];
401
-			foreach ($groups as $group) {
402
-				$groupItem = $groupManager->get($group);
403
-				if ($groupItem instanceof \OCP\IGroup) {
404
-					$groupsList[] = $groupManager->get($group);
405
-				}
406
-			}
407
-			$appManager->enableAppForGroups($appId, $groupsList);
408
-		} else {
409
-			$appManager->enableApp($appId);
410
-		}
411
-
412
-		$info = self::getAppInfo($appId);
413
-		if(isset($info['settings']) && is_array($info['settings'])) {
414
-			$appPath = self::getAppPath($appId);
415
-			self::registerAutoloading($appId, $appPath);
416
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
417
-		}
418
-	}
419
-
420
-	/**
421
-	 * @param string $app
422
-	 * @return bool
423
-	 */
424
-	public static function removeApp($app) {
425
-		if (self::isShipped($app)) {
426
-			return false;
427
-		}
428
-
429
-		$installer = new Installer(
430
-			\OC::$server->getAppFetcher(),
431
-			\OC::$server->getAppManager(),
432
-			\OC::$server->getHTTPClientService(),
433
-			\OC::$server->getTempManager(),
434
-			\OC::$server->getLogger(),
435
-			\OC::$server->getConfig()
436
-		);
437
-		return $installer->removeApp($app);
438
-	}
439
-
440
-	/**
441
-	 * This function set an app as disabled in appconfig.
442
-	 *
443
-	 * @param string $app app
444
-	 * @throws Exception
445
-	 */
446
-	public static function disable($app) {
447
-		// flush
448
-		self::$enabledAppsCache = array();
449
-
450
-		// run uninstall steps
451
-		$appData = OC_App::getAppInfo($app);
452
-		if (!is_null($appData)) {
453
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
454
-		}
455
-
456
-		// emit disable hook - needed anymore ?
457
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
458
-
459
-		// finally disable it
460
-		$appManager = \OC::$server->getAppManager();
461
-		$appManager->disableApp($app);
462
-	}
463
-
464
-	// This is private as well. It simply works, so don't ask for more details
465
-	private static function proceedNavigation($list) {
466
-		usort($list, function($a, $b) {
467
-			if (isset($a['order']) && isset($b['order'])) {
468
-				return ($a['order'] < $b['order']) ? -1 : 1;
469
-			} else if (isset($a['order']) || isset($b['order'])) {
470
-				return isset($a['order']) ? -1 : 1;
471
-			} else {
472
-				return ($a['name'] < $b['name']) ? -1 : 1;
473
-			}
474
-		});
475
-
476
-		$activeAppIndex = -1;
477
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
478
-		foreach ($list as $index => &$navEntry) {
479
-			$navEntry['showInHeader'] = true;
480
-			if ($navEntry['id'] == $activeApp) {
481
-				$navEntry['active'] = true;
482
-				$activeAppIndex = $index;
483
-			} else {
484
-				$navEntry['active'] = false;
485
-			}
486
-		}
487
-		unset($navEntry);
488
-
489
-		if (count($list) <= 8) {
490
-			return $list;
491
-		}
492
-
493
-		$headerIconCount = 7;
494
-		if($activeAppIndex > ($headerIconCount-1)) {
495
-			$active = $list[$activeAppIndex];
496
-			$lastInHeader = $list[$headerIconCount-1];
497
-			$list[$headerIconCount-1] = $active;
498
-			$list[$activeAppIndex] = $lastInHeader;
499
-		}
500
-
501
-		foreach ($list as $index => &$navEntry) {
502
-			if($index >= $headerIconCount) {
503
-				$navEntry['showInHeader'] = false;
504
-			}
505
-		}
506
-
507
-		return $list;
508
-	}
509
-
510
-	public static function proceedAppNavigation($entries) {
511
-		$activeAppIndex = -1;
512
-		$list = self::proceedNavigation($entries);
513
-
514
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
515
-		foreach ($list as $index => &$navEntry) {
516
-			if ($navEntry['id'] == $activeApp) {
517
-				$navEntry['active'] = true;
518
-				$activeAppIndex = $index;
519
-			} else {
520
-				$navEntry['active'] = false;
521
-			}
522
-		}
523
-
524
-
525
-		if (count($list) <= 8) {
526
-			return $list;
527
-		}
528
-
529
-		$headerIconCount = 7;
530
-		// move active item to last position
531
-		if($activeAppIndex > ($headerIconCount-1)) {
532
-			$active = $list[$activeAppIndex];
533
-			$lastInHeader = $list[$headerIconCount-1];
534
-			$list[$headerIconCount-1] = $active;
535
-			$list[$activeAppIndex] = $lastInHeader;
536
-		}
537
-		$list = array_slice($list, 0, $headerIconCount);
538
-
539
-		return $list;
540
-	}
541
-
542
-	/**
543
-	 * Get the path where to install apps
544
-	 *
545
-	 * @return string|false
546
-	 */
547
-	public static function getInstallPath() {
548
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
549
-			return false;
550
-		}
551
-
552
-		foreach (OC::$APPSROOTS as $dir) {
553
-			if (isset($dir['writable']) && $dir['writable'] === true) {
554
-				return $dir['path'];
555
-			}
556
-		}
557
-
558
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
559
-		return null;
560
-	}
561
-
562
-
563
-	/**
564
-	 * search for an app in all app-directories
565
-	 *
566
-	 * @param string $appId
567
-	 * @return false|string
568
-	 */
569
-	public static function findAppInDirectories($appId) {
570
-		$sanitizedAppId = self::cleanAppId($appId);
571
-		if($sanitizedAppId !== $appId) {
572
-			return false;
573
-		}
574
-		static $app_dir = array();
575
-
576
-		if (isset($app_dir[$appId])) {
577
-			return $app_dir[$appId];
578
-		}
579
-
580
-		$possibleApps = array();
581
-		foreach (OC::$APPSROOTS as $dir) {
582
-			if (file_exists($dir['path'] . '/' . $appId)) {
583
-				$possibleApps[] = $dir;
584
-			}
585
-		}
586
-
587
-		if (empty($possibleApps)) {
588
-			return false;
589
-		} elseif (count($possibleApps) === 1) {
590
-			$dir = array_shift($possibleApps);
591
-			$app_dir[$appId] = $dir;
592
-			return $dir;
593
-		} else {
594
-			$versionToLoad = array();
595
-			foreach ($possibleApps as $possibleApp) {
596
-				$version = self::getAppVersionByPath($possibleApp['path']);
597
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
598
-					$versionToLoad = array(
599
-						'dir' => $possibleApp,
600
-						'version' => $version,
601
-					);
602
-				}
603
-			}
604
-			$app_dir[$appId] = $versionToLoad['dir'];
605
-			return $versionToLoad['dir'];
606
-			//TODO - write test
607
-		}
608
-	}
609
-
610
-	/**
611
-	 * Get the directory for the given app.
612
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
613
-	 *
614
-	 * @param string $appId
615
-	 * @return string|false
616
-	 */
617
-	public static function getAppPath($appId) {
618
-		if ($appId === null || trim($appId) === '') {
619
-			return false;
620
-		}
621
-
622
-		if (($dir = self::findAppInDirectories($appId)) != false) {
623
-			return $dir['path'] . '/' . $appId;
624
-		}
625
-		return false;
626
-	}
627
-
628
-	/**
629
-	 * Get the path for the given app on the access
630
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
631
-	 *
632
-	 * @param string $appId
633
-	 * @return string|false
634
-	 */
635
-	public static function getAppWebPath($appId) {
636
-		if (($dir = self::findAppInDirectories($appId)) != false) {
637
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
638
-		}
639
-		return false;
640
-	}
641
-
642
-	/**
643
-	 * get the last version of the app from appinfo/info.xml
644
-	 *
645
-	 * @param string $appId
646
-	 * @param bool $useCache
647
-	 * @return string
648
-	 */
649
-	public static function getAppVersion($appId, $useCache = true) {
650
-		if($useCache && isset(self::$appVersion[$appId])) {
651
-			return self::$appVersion[$appId];
652
-		}
653
-
654
-		$file = self::getAppPath($appId);
655
-		self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
656
-		return self::$appVersion[$appId];
657
-	}
658
-
659
-	/**
660
-	 * get app's version based on it's path
661
-	 *
662
-	 * @param string $path
663
-	 * @return string
664
-	 */
665
-	public static function getAppVersionByPath($path) {
666
-		$infoFile = $path . '/appinfo/info.xml';
667
-		$appData = self::getAppInfo($infoFile, true);
668
-		return isset($appData['version']) ? $appData['version'] : '';
669
-	}
670
-
671
-
672
-	/**
673
-	 * Read all app metadata from the info.xml file
674
-	 *
675
-	 * @param string $appId id of the app or the path of the info.xml file
676
-	 * @param bool $path
677
-	 * @param string $lang
678
-	 * @return array|null
679
-	 * @note all data is read from info.xml, not just pre-defined fields
680
-	 */
681
-	public static function getAppInfo($appId, $path = false, $lang = null) {
682
-		if ($path) {
683
-			$file = $appId;
684
-		} else {
685
-			if ($lang === null && isset(self::$appInfo[$appId])) {
686
-				return self::$appInfo[$appId];
687
-			}
688
-			$appPath = self::getAppPath($appId);
689
-			if($appPath === false) {
690
-				return null;
691
-			}
692
-			$file = $appPath . '/appinfo/info.xml';
693
-		}
694
-
695
-		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
696
-		$data = $parser->parse($file);
697
-
698
-		if (is_array($data)) {
699
-			$data = OC_App::parseAppInfo($data, $lang);
700
-		}
701
-		if(isset($data['ocsid'])) {
702
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
703
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
704
-				$data['ocsid'] = $storedId;
705
-			}
706
-		}
707
-
708
-		if ($lang === null) {
709
-			self::$appInfo[$appId] = $data;
710
-		}
711
-
712
-		return $data;
713
-	}
714
-
715
-	/**
716
-	 * Returns the navigation
717
-	 *
718
-	 * @return array
719
-	 *
720
-	 * This function returns an array containing all entries added. The
721
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
722
-	 * given for each app the following keys exist:
723
-	 *   - active: boolean, signals if the user is on this navigation entry
724
-	 */
725
-	public static function getNavigation() {
726
-		$entries = OC::$server->getNavigationManager()->getAll();
727
-		return self::proceedNavigation($entries);
728
-	}
729
-
730
-	/**
731
-	 * Returns the navigation inside the header bar
732
-	 *
733
-	 * @return array
734
-	 *
735
-	 * This function returns an array containing all entries added. The
736
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
737
-	 * given for each app the following keys exist:
738
-	 *   - active: boolean, signals if the user is on this navigation entry
739
-	 */
740
-	public static function getHeaderNavigation() {
741
-		$entries = OC::$server->getNavigationManager()->getAll();
742
-		return self::proceedAppNavigation($entries);
743
-	}
744
-
745
-	/**
746
-	 * Returns the Settings Navigation
747
-	 *
748
-	 * @return string[]
749
-	 *
750
-	 * This function returns an array containing all settings pages added. The
751
-	 * entries are sorted by the key 'order' ascending.
752
-	 */
753
-	public static function getSettingsNavigation() {
754
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
755
-		return self::proceedNavigation($entries);
756
-	}
757
-
758
-	/**
759
-	 * get the id of loaded app
760
-	 *
761
-	 * @return string
762
-	 */
763
-	public static function getCurrentApp() {
764
-		$request = \OC::$server->getRequest();
765
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
766
-		$topFolder = substr($script, 0, strpos($script, '/'));
767
-		if (empty($topFolder)) {
768
-			$path_info = $request->getPathInfo();
769
-			if ($path_info) {
770
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
771
-			}
772
-		}
773
-		if ($topFolder == 'apps') {
774
-			$length = strlen($topFolder);
775
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
776
-		} else {
777
-			return $topFolder;
778
-		}
779
-	}
780
-
781
-	/**
782
-	 * @param string $type
783
-	 * @return array
784
-	 */
785
-	public static function getForms($type) {
786
-		$forms = array();
787
-		switch ($type) {
788
-			case 'admin':
789
-				$source = self::$adminForms;
790
-				break;
791
-			case 'personal':
792
-				$source = self::$personalForms;
793
-				break;
794
-			default:
795
-				return array();
796
-		}
797
-		foreach ($source as $form) {
798
-			$forms[] = include $form;
799
-		}
800
-		return $forms;
801
-	}
802
-
803
-	/**
804
-	 * register an admin form to be shown
805
-	 *
806
-	 * @param string $app
807
-	 * @param string $page
808
-	 */
809
-	public static function registerAdmin($app, $page) {
810
-		self::$adminForms[] = $app . '/' . $page . '.php';
811
-	}
812
-
813
-	/**
814
-	 * register a personal form to be shown
815
-	 * @param string $app
816
-	 * @param string $page
817
-	 */
818
-	public static function registerPersonal($app, $page) {
819
-		self::$personalForms[] = $app . '/' . $page . '.php';
820
-	}
821
-
822
-	/**
823
-	 * @param array $entry
824
-	 */
825
-	public static function registerLogIn(array $entry) {
826
-		self::$altLogin[] = $entry;
827
-	}
828
-
829
-	/**
830
-	 * @return array
831
-	 */
832
-	public static function getAlternativeLogIns() {
833
-		return self::$altLogin;
834
-	}
835
-
836
-	/**
837
-	 * get a list of all apps in the apps folder
838
-	 *
839
-	 * @return array an array of app names (string IDs)
840
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
841
-	 */
842
-	public static function getAllApps() {
843
-
844
-		$apps = array();
845
-
846
-		foreach (OC::$APPSROOTS as $apps_dir) {
847
-			if (!is_readable($apps_dir['path'])) {
848
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
849
-				continue;
850
-			}
851
-			$dh = opendir($apps_dir['path']);
852
-
853
-			if (is_resource($dh)) {
854
-				while (($file = readdir($dh)) !== false) {
855
-
856
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
857
-
858
-						$apps[] = $file;
859
-					}
860
-				}
861
-			}
862
-		}
863
-
864
-		return $apps;
865
-	}
866
-
867
-	/**
868
-	 * List all apps, this is used in apps.php
869
-	 *
870
-	 * @return array
871
-	 */
872
-	public function listAllApps() {
873
-		$installedApps = OC_App::getAllApps();
874
-
875
-		//we don't want to show configuration for these
876
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
877
-		$appList = array();
878
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
879
-		$urlGenerator = \OC::$server->getURLGenerator();
880
-
881
-		foreach ($installedApps as $app) {
882
-			if (array_search($app, $blacklist) === false) {
883
-
884
-				$info = OC_App::getAppInfo($app, false, $langCode);
885
-				if (!is_array($info)) {
886
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
887
-					continue;
888
-				}
889
-
890
-				if (!isset($info['name'])) {
891
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
892
-					continue;
893
-				}
894
-
895
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
896
-				$info['groups'] = null;
897
-				if ($enabled === 'yes') {
898
-					$active = true;
899
-				} else if ($enabled === 'no') {
900
-					$active = false;
901
-				} else {
902
-					$active = true;
903
-					$info['groups'] = $enabled;
904
-				}
905
-
906
-				$info['active'] = $active;
907
-
908
-				if (self::isShipped($app)) {
909
-					$info['internal'] = true;
910
-					$info['level'] = self::officialApp;
911
-					$info['removable'] = false;
912
-				} else {
913
-					$info['internal'] = false;
914
-					$info['removable'] = true;
915
-				}
916
-
917
-				$appPath = self::getAppPath($app);
918
-				if($appPath !== false) {
919
-					$appIcon = $appPath . '/img/' . $app . '.svg';
920
-					if (file_exists($appIcon)) {
921
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
922
-						$info['previewAsIcon'] = true;
923
-					} else {
924
-						$appIcon = $appPath . '/img/app.svg';
925
-						if (file_exists($appIcon)) {
926
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
927
-							$info['previewAsIcon'] = true;
928
-						}
929
-					}
930
-				}
931
-				// fix documentation
932
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
933
-					foreach ($info['documentation'] as $key => $url) {
934
-						// If it is not an absolute URL we assume it is a key
935
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
936
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
937
-							$url = $urlGenerator->linkToDocs($url);
938
-						}
939
-
940
-						$info['documentation'][$key] = $url;
941
-					}
942
-				}
943
-
944
-				$info['version'] = OC_App::getAppVersion($app);
945
-				$appList[] = $info;
946
-			}
947
-		}
948
-
949
-		return $appList;
950
-	}
951
-
952
-	/**
953
-	 * Returns the internal app ID or false
954
-	 * @param string $ocsID
955
-	 * @return string|false
956
-	 */
957
-	public static function getInternalAppIdByOcs($ocsID) {
958
-		if(is_numeric($ocsID)) {
959
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
960
-			if(array_search($ocsID, $idArray)) {
961
-				return array_search($ocsID, $idArray);
962
-			}
963
-		}
964
-		return false;
965
-	}
966
-
967
-	public static function shouldUpgrade($app) {
968
-		$versions = self::getAppVersions();
969
-		$currentVersion = OC_App::getAppVersion($app);
970
-		if ($currentVersion && isset($versions[$app])) {
971
-			$installedVersion = $versions[$app];
972
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
973
-				return true;
974
-			}
975
-		}
976
-		return false;
977
-	}
978
-
979
-	/**
980
-	 * Adjust the number of version parts of $version1 to match
981
-	 * the number of version parts of $version2.
982
-	 *
983
-	 * @param string $version1 version to adjust
984
-	 * @param string $version2 version to take the number of parts from
985
-	 * @return string shortened $version1
986
-	 */
987
-	private static function adjustVersionParts($version1, $version2) {
988
-		$version1 = explode('.', $version1);
989
-		$version2 = explode('.', $version2);
990
-		// reduce $version1 to match the number of parts in $version2
991
-		while (count($version1) > count($version2)) {
992
-			array_pop($version1);
993
-		}
994
-		// if $version1 does not have enough parts, add some
995
-		while (count($version1) < count($version2)) {
996
-			$version1[] = '0';
997
-		}
998
-		return implode('.', $version1);
999
-	}
1000
-
1001
-	/**
1002
-	 * Check whether the current ownCloud version matches the given
1003
-	 * application's version requirements.
1004
-	 *
1005
-	 * The comparison is made based on the number of parts that the
1006
-	 * app info version has. For example for ownCloud 6.0.3 if the
1007
-	 * app info version is expecting version 6.0, the comparison is
1008
-	 * made on the first two parts of the ownCloud version.
1009
-	 * This means that it's possible to specify "requiremin" => 6
1010
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
1011
-	 *
1012
-	 * @param string $ocVersion ownCloud version to check against
1013
-	 * @param array $appInfo app info (from xml)
1014
-	 *
1015
-	 * @return boolean true if compatible, otherwise false
1016
-	 */
1017
-	public static function isAppCompatible($ocVersion, $appInfo) {
1018
-		$requireMin = '';
1019
-		$requireMax = '';
1020
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
1021
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
1022
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1023
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1024
-		} else if (isset($appInfo['requiremin'])) {
1025
-			$requireMin = $appInfo['requiremin'];
1026
-		} else if (isset($appInfo['require'])) {
1027
-			$requireMin = $appInfo['require'];
1028
-		}
1029
-
1030
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
1031
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
1032
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1033
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1034
-		} else if (isset($appInfo['requiremax'])) {
1035
-			$requireMax = $appInfo['requiremax'];
1036
-		}
1037
-
1038
-		if (is_array($ocVersion)) {
1039
-			$ocVersion = implode('.', $ocVersion);
1040
-		}
1041
-
1042
-		if (!empty($requireMin)
1043
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1044
-		) {
1045
-
1046
-			return false;
1047
-		}
1048
-
1049
-		if (!empty($requireMax)
1050
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1051
-		) {
1052
-			return false;
1053
-		}
1054
-
1055
-		return true;
1056
-	}
1057
-
1058
-	/**
1059
-	 * get the installed version of all apps
1060
-	 */
1061
-	public static function getAppVersions() {
1062
-		static $versions;
1063
-
1064
-		if(!$versions) {
1065
-			$appConfig = \OC::$server->getAppConfig();
1066
-			$versions = $appConfig->getValues(false, 'installed_version');
1067
-		}
1068
-		return $versions;
1069
-	}
1070
-
1071
-	/**
1072
-	 * @param string $app
1073
-	 * @param \OCP\IConfig $config
1074
-	 * @param \OCP\IL10N $l
1075
-	 * @return bool
1076
-	 *
1077
-	 * @throws Exception if app is not compatible with this version of ownCloud
1078
-	 * @throws Exception if no app-name was specified
1079
-	 */
1080
-	public function installApp($app,
1081
-							   \OCP\IConfig $config,
1082
-							   \OCP\IL10N $l) {
1083
-		if ($app !== false) {
1084
-			// check if the app is compatible with this version of ownCloud
1085
-			$info = self::getAppInfo($app);
1086
-			if(!is_array($info)) {
1087
-				throw new \Exception(
1088
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1089
-						[$info['name']]
1090
-					)
1091
-				);
1092
-			}
1093
-
1094
-			$version = \OCP\Util::getVersion();
1095
-			if (!self::isAppCompatible($version, $info)) {
1096
-				throw new \Exception(
1097
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1098
-						array($info['name'])
1099
-					)
1100
-				);
1101
-			}
1102
-
1103
-			// check for required dependencies
1104
-			self::checkAppDependencies($config, $l, $info);
1105
-
1106
-			$config->setAppValue($app, 'enabled', 'yes');
1107
-			if (isset($appData['id'])) {
1108
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1109
-			}
1110
-
1111
-			if(isset($info['settings']) && is_array($info['settings'])) {
1112
-				$appPath = self::getAppPath($app);
1113
-				self::registerAutoloading($app, $appPath);
1114
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1115
-			}
1116
-
1117
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1118
-		} else {
1119
-			if(empty($appName) ) {
1120
-				throw new \Exception($l->t("No app name specified"));
1121
-			} else {
1122
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1123
-			}
1124
-		}
1125
-
1126
-		return $app;
1127
-	}
1128
-
1129
-	/**
1130
-	 * update the database for the app and call the update script
1131
-	 *
1132
-	 * @param string $appId
1133
-	 * @return bool
1134
-	 */
1135
-	public static function updateApp($appId) {
1136
-		$appPath = self::getAppPath($appId);
1137
-		if($appPath === false) {
1138
-			return false;
1139
-		}
1140
-		$appData = self::getAppInfo($appId);
1141
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1142
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1143
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1144
-		}
1145
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1146
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1147
-		unset(self::$appVersion[$appId]);
1148
-		// run upgrade code
1149
-		if (file_exists($appPath . '/appinfo/update.php')) {
1150
-			self::loadApp($appId);
1151
-			include $appPath . '/appinfo/update.php';
1152
-		}
1153
-		self::setupBackgroundJobs($appData['background-jobs']);
1154
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1155
-			$appPath = self::getAppPath($appId);
1156
-			self::registerAutoloading($appId, $appPath);
1157
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1158
-		}
1159
-
1160
-		//set remote/public handlers
1161
-		if (array_key_exists('ocsid', $appData)) {
1162
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1163
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1164
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1165
-		}
1166
-		foreach ($appData['remote'] as $name => $path) {
1167
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1168
-		}
1169
-		foreach ($appData['public'] as $name => $path) {
1170
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1171
-		}
1172
-
1173
-		self::setAppTypes($appId);
1174
-
1175
-		$version = \OC_App::getAppVersion($appId);
1176
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1177
-
1178
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1179
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1180
-		));
1181
-
1182
-		return true;
1183
-	}
1184
-
1185
-	/**
1186
-	 * @param string $appId
1187
-	 * @param string[] $steps
1188
-	 * @throws \OC\NeedsUpdateException
1189
-	 */
1190
-	public static function executeRepairSteps($appId, array $steps) {
1191
-		if (empty($steps)) {
1192
-			return;
1193
-		}
1194
-		// load the app
1195
-		self::loadApp($appId);
1196
-
1197
-		$dispatcher = OC::$server->getEventDispatcher();
1198
-
1199
-		// load the steps
1200
-		$r = new Repair([], $dispatcher);
1201
-		foreach ($steps as $step) {
1202
-			try {
1203
-				$r->addStep($step);
1204
-			} catch (Exception $ex) {
1205
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1206
-				\OC::$server->getLogger()->logException($ex);
1207
-			}
1208
-		}
1209
-		// run the steps
1210
-		$r->run();
1211
-	}
1212
-
1213
-	public static function setupBackgroundJobs(array $jobs) {
1214
-		$queue = \OC::$server->getJobList();
1215
-		foreach ($jobs as $job) {
1216
-			$queue->add($job);
1217
-		}
1218
-	}
1219
-
1220
-	/**
1221
-	 * @param string $appId
1222
-	 * @param string[] $steps
1223
-	 */
1224
-	private static function setupLiveMigrations($appId, array $steps) {
1225
-		$queue = \OC::$server->getJobList();
1226
-		foreach ($steps as $step) {
1227
-			$queue->add('OC\Migration\BackgroundRepair', [
1228
-				'app' => $appId,
1229
-				'step' => $step]);
1230
-		}
1231
-	}
1232
-
1233
-	/**
1234
-	 * @param string $appId
1235
-	 * @return \OC\Files\View|false
1236
-	 */
1237
-	public static function getStorage($appId) {
1238
-		if (OC_App::isEnabled($appId)) { //sanity check
1239
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1240
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1241
-				if (!$view->file_exists($appId)) {
1242
-					$view->mkdir($appId);
1243
-				}
1244
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1245
-			} else {
1246
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1247
-				return false;
1248
-			}
1249
-		} else {
1250
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1251
-			return false;
1252
-		}
1253
-	}
1254
-
1255
-	protected static function findBestL10NOption($options, $lang) {
1256
-		$fallback = $similarLangFallback = $englishFallback = false;
1257
-
1258
-		$lang = strtolower($lang);
1259
-		$similarLang = $lang;
1260
-		if (strpos($similarLang, '_')) {
1261
-			// For "de_DE" we want to find "de" and the other way around
1262
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1263
-		}
1264
-
1265
-		foreach ($options as $option) {
1266
-			if (is_array($option)) {
1267
-				if ($fallback === false) {
1268
-					$fallback = $option['@value'];
1269
-				}
1270
-
1271
-				if (!isset($option['@attributes']['lang'])) {
1272
-					continue;
1273
-				}
1274
-
1275
-				$attributeLang = strtolower($option['@attributes']['lang']);
1276
-				if ($attributeLang === $lang) {
1277
-					return $option['@value'];
1278
-				}
1279
-
1280
-				if ($attributeLang === $similarLang) {
1281
-					$similarLangFallback = $option['@value'];
1282
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1283
-					if ($similarLangFallback === false) {
1284
-						$similarLangFallback =  $option['@value'];
1285
-					}
1286
-				}
1287
-			} else {
1288
-				$englishFallback = $option;
1289
-			}
1290
-		}
1291
-
1292
-		if ($similarLangFallback !== false) {
1293
-			return $similarLangFallback;
1294
-		} else if ($englishFallback !== false) {
1295
-			return $englishFallback;
1296
-		}
1297
-		return (string) $fallback;
1298
-	}
1299
-
1300
-	/**
1301
-	 * parses the app data array and enhanced the 'description' value
1302
-	 *
1303
-	 * @param array $data the app data
1304
-	 * @param string $lang
1305
-	 * @return array improved app data
1306
-	 */
1307
-	public static function parseAppInfo(array $data, $lang = null) {
1308
-
1309
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1310
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1311
-		}
1312
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1313
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1314
-		}
1315
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1316
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1317
-		} else if (isset($data['description']) && is_string($data['description'])) {
1318
-			$data['description'] = trim($data['description']);
1319
-		} else  {
1320
-			$data['description'] = '';
1321
-		}
1322
-
1323
-		return $data;
1324
-	}
1325
-
1326
-	/**
1327
-	 * @param \OCP\IConfig $config
1328
-	 * @param \OCP\IL10N $l
1329
-	 * @param array $info
1330
-	 * @throws \Exception
1331
-	 */
1332
-	protected static function checkAppDependencies($config, $l, $info) {
1333
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1334
-		$missing = $dependencyAnalyzer->analyze($info);
1335
-		if (!empty($missing)) {
1336
-			$missingMsg = join(PHP_EOL, $missing);
1337
-			throw new \Exception(
1338
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1339
-					[$info['name'], $missingMsg]
1340
-				)
1341
-			);
1342
-		}
1343
-	}
64
+    static private $appVersion = [];
65
+    static private $adminForms = array();
66
+    static private $personalForms = array();
67
+    static private $appInfo = array();
68
+    static private $appTypes = array();
69
+    static private $loadedApps = array();
70
+    static private $altLogin = array();
71
+    static private $alreadyRegistered = [];
72
+    const officialApp = 200;
73
+
74
+    /**
75
+     * clean the appId
76
+     *
77
+     * @param string|boolean $app AppId that needs to be cleaned
78
+     * @return string
79
+     */
80
+    public static function cleanAppId($app) {
81
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
+    }
83
+
84
+    /**
85
+     * Check if an app is loaded
86
+     *
87
+     * @param string $app
88
+     * @return bool
89
+     */
90
+    public static function isAppLoaded($app) {
91
+        return in_array($app, self::$loadedApps, true);
92
+    }
93
+
94
+    /**
95
+     * loads all apps
96
+     *
97
+     * @param string[] | string | null $types
98
+     * @return bool
99
+     *
100
+     * This function walks through the ownCloud directory and loads all apps
101
+     * it can find. A directory contains an app if the file /appinfo/info.xml
102
+     * exists.
103
+     *
104
+     * if $types is set, only apps of those types will be loaded
105
+     */
106
+    public static function loadApps($types = null) {
107
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
+            return false;
109
+        }
110
+        // Load the enabled apps here
111
+        $apps = self::getEnabledApps();
112
+
113
+        // Add each apps' folder as allowed class path
114
+        foreach($apps as $app) {
115
+            $path = self::getAppPath($app);
116
+            if($path !== false) {
117
+                self::registerAutoloading($app, $path);
118
+            }
119
+        }
120
+
121
+        // prevent app.php from printing output
122
+        ob_start();
123
+        foreach ($apps as $app) {
124
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
+                self::loadApp($app);
126
+            }
127
+        }
128
+        ob_end_clean();
129
+
130
+        return true;
131
+    }
132
+
133
+    /**
134
+     * load a single app
135
+     *
136
+     * @param string $app
137
+     */
138
+    public static function loadApp($app) {
139
+        self::$loadedApps[] = $app;
140
+        $appPath = self::getAppPath($app);
141
+        if($appPath === false) {
142
+            return;
143
+        }
144
+
145
+        // in case someone calls loadApp() directly
146
+        self::registerAutoloading($app, $appPath);
147
+
148
+        if (is_file($appPath . '/appinfo/app.php')) {
149
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
+            self::requireAppFile($app);
151
+            if (self::isType($app, array('authentication'))) {
152
+                // since authentication apps affect the "is app enabled for group" check,
153
+                // the enabled apps cache needs to be cleared to make sure that the
154
+                // next time getEnableApps() is called it will also include apps that were
155
+                // enabled for groups
156
+                self::$enabledAppsCache = array();
157
+            }
158
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
159
+        }
160
+
161
+        $info = self::getAppInfo($app);
162
+        if (!empty($info['activity']['filters'])) {
163
+            foreach ($info['activity']['filters'] as $filter) {
164
+                \OC::$server->getActivityManager()->registerFilter($filter);
165
+            }
166
+        }
167
+        if (!empty($info['activity']['settings'])) {
168
+            foreach ($info['activity']['settings'] as $setting) {
169
+                \OC::$server->getActivityManager()->registerSetting($setting);
170
+            }
171
+        }
172
+        if (!empty($info['activity']['providers'])) {
173
+            foreach ($info['activity']['providers'] as $provider) {
174
+                \OC::$server->getActivityManager()->registerProvider($provider);
175
+            }
176
+        }
177
+    }
178
+
179
+    /**
180
+     * @internal
181
+     * @param string $app
182
+     * @param string $path
183
+     */
184
+    public static function registerAutoloading($app, $path) {
185
+        $key = $app . '-' . $path;
186
+        if(isset(self::$alreadyRegistered[$key])) {
187
+            return;
188
+        }
189
+        self::$alreadyRegistered[$key] = true;
190
+        // Register on PSR-4 composer autoloader
191
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
+        \OC::$server->registerNamespace($app, $appNamespace);
193
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
194
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
195
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
196
+        }
197
+
198
+        // Register on legacy autoloader
199
+        \OC::$loader->addValidRoot($path);
200
+    }
201
+
202
+    /**
203
+     * Load app.php from the given app
204
+     *
205
+     * @param string $app app name
206
+     */
207
+    private static function requireAppFile($app) {
208
+        try {
209
+            // encapsulated here to avoid variable scope conflicts
210
+            require_once $app . '/appinfo/app.php';
211
+        } catch (Error $ex) {
212
+            \OC::$server->getLogger()->logException($ex);
213
+            $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
214
+            if (!in_array($app, $blacklist)) {
215
+                self::disable($app);
216
+            }
217
+        }
218
+    }
219
+
220
+    /**
221
+     * check if an app is of a specific type
222
+     *
223
+     * @param string $app
224
+     * @param string|array $types
225
+     * @return bool
226
+     */
227
+    public static function isType($app, $types) {
228
+        if (is_string($types)) {
229
+            $types = array($types);
230
+        }
231
+        $appTypes = self::getAppTypes($app);
232
+        foreach ($types as $type) {
233
+            if (array_search($type, $appTypes) !== false) {
234
+                return true;
235
+            }
236
+        }
237
+        return false;
238
+    }
239
+
240
+    /**
241
+     * get the types of an app
242
+     *
243
+     * @param string $app
244
+     * @return array
245
+     */
246
+    private static function getAppTypes($app) {
247
+        //load the cache
248
+        if (count(self::$appTypes) == 0) {
249
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
250
+        }
251
+
252
+        if (isset(self::$appTypes[$app])) {
253
+            return explode(',', self::$appTypes[$app]);
254
+        } else {
255
+            return array();
256
+        }
257
+    }
258
+
259
+    /**
260
+     * read app types from info.xml and cache them in the database
261
+     */
262
+    public static function setAppTypes($app) {
263
+        $appData = self::getAppInfo($app);
264
+        if(!is_array($appData)) {
265
+            return;
266
+        }
267
+
268
+        if (isset($appData['types'])) {
269
+            $appTypes = implode(',', $appData['types']);
270
+        } else {
271
+            $appTypes = '';
272
+            $appData['types'] = [];
273
+        }
274
+
275
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
276
+
277
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
278
+            $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
279
+            if ($enabled !== 'yes' && $enabled !== 'no') {
280
+                \OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
281
+            }
282
+        }
283
+    }
284
+
285
+    /**
286
+     * check if app is shipped
287
+     *
288
+     * @param string $appId the id of the app to check
289
+     * @return bool
290
+     *
291
+     * Check if an app that is installed is a shipped app or installed from the appstore.
292
+     */
293
+    public static function isShipped($appId) {
294
+        return \OC::$server->getAppManager()->isShipped($appId);
295
+    }
296
+
297
+    /**
298
+     * get all enabled apps
299
+     */
300
+    protected static $enabledAppsCache = array();
301
+
302
+    /**
303
+     * Returns apps enabled for the current user.
304
+     *
305
+     * @param bool $forceRefresh whether to refresh the cache
306
+     * @param bool $all whether to return apps for all users, not only the
307
+     * currently logged in one
308
+     * @return string[]
309
+     */
310
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
311
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
312
+            return array();
313
+        }
314
+        // in incognito mode or when logged out, $user will be false,
315
+        // which is also the case during an upgrade
316
+        $appManager = \OC::$server->getAppManager();
317
+        if ($all) {
318
+            $user = null;
319
+        } else {
320
+            $user = \OC::$server->getUserSession()->getUser();
321
+        }
322
+
323
+        if (is_null($user)) {
324
+            $apps = $appManager->getInstalledApps();
325
+        } else {
326
+            $apps = $appManager->getEnabledAppsForUser($user);
327
+        }
328
+        $apps = array_filter($apps, function ($app) {
329
+            return $app !== 'files';//we add this manually
330
+        });
331
+        sort($apps);
332
+        array_unshift($apps, 'files');
333
+        return $apps;
334
+    }
335
+
336
+    /**
337
+     * checks whether or not an app is enabled
338
+     *
339
+     * @param string $app app
340
+     * @return bool
341
+     *
342
+     * This function checks whether or not an app is enabled.
343
+     */
344
+    public static function isEnabled($app) {
345
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
346
+    }
347
+
348
+    /**
349
+     * enables an app
350
+     *
351
+     * @param string $appId
352
+     * @param array $groups (optional) when set, only these groups will have access to the app
353
+     * @throws \Exception
354
+     * @return void
355
+     *
356
+     * This function set an app as enabled in appconfig.
357
+     */
358
+    public function enable($appId,
359
+                            $groups = null) {
360
+        self::$enabledAppsCache = []; // flush
361
+        $l = \OC::$server->getL10N('core');
362
+        $config = \OC::$server->getConfig();
363
+
364
+        // Check if app is already downloaded
365
+        $installer = new Installer(
366
+            \OC::$server->getAppFetcher(),
367
+            \OC::$server->getAppManager(),
368
+            \OC::$server->getHTTPClientService(),
369
+            \OC::$server->getTempManager(),
370
+            \OC::$server->getLogger(),
371
+            \OC::$server->getConfig()
372
+        );
373
+        $isDownloaded = $installer->isDownloaded($appId);
374
+
375
+        if(!$isDownloaded) {
376
+            $installer->downloadApp($appId);
377
+        }
378
+
379
+        if (!Installer::isInstalled($appId)) {
380
+            $appId = self::installApp(
381
+                $appId,
382
+                $config,
383
+                $l
384
+            );
385
+            $appPath = self::getAppPath($appId);
386
+            self::registerAutoloading($appId, $appPath);
387
+            $installer->installApp($appId);
388
+        } else {
389
+            // check for required dependencies
390
+            $info = self::getAppInfo($appId);
391
+            self::checkAppDependencies($config, $l, $info);
392
+            $appPath = self::getAppPath($appId);
393
+            self::registerAutoloading($appId, $appPath);
394
+            $installer->installApp($appId);
395
+        }
396
+
397
+        $appManager = \OC::$server->getAppManager();
398
+        if (!is_null($groups)) {
399
+            $groupManager = \OC::$server->getGroupManager();
400
+            $groupsList = [];
401
+            foreach ($groups as $group) {
402
+                $groupItem = $groupManager->get($group);
403
+                if ($groupItem instanceof \OCP\IGroup) {
404
+                    $groupsList[] = $groupManager->get($group);
405
+                }
406
+            }
407
+            $appManager->enableAppForGroups($appId, $groupsList);
408
+        } else {
409
+            $appManager->enableApp($appId);
410
+        }
411
+
412
+        $info = self::getAppInfo($appId);
413
+        if(isset($info['settings']) && is_array($info['settings'])) {
414
+            $appPath = self::getAppPath($appId);
415
+            self::registerAutoloading($appId, $appPath);
416
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
417
+        }
418
+    }
419
+
420
+    /**
421
+     * @param string $app
422
+     * @return bool
423
+     */
424
+    public static function removeApp($app) {
425
+        if (self::isShipped($app)) {
426
+            return false;
427
+        }
428
+
429
+        $installer = new Installer(
430
+            \OC::$server->getAppFetcher(),
431
+            \OC::$server->getAppManager(),
432
+            \OC::$server->getHTTPClientService(),
433
+            \OC::$server->getTempManager(),
434
+            \OC::$server->getLogger(),
435
+            \OC::$server->getConfig()
436
+        );
437
+        return $installer->removeApp($app);
438
+    }
439
+
440
+    /**
441
+     * This function set an app as disabled in appconfig.
442
+     *
443
+     * @param string $app app
444
+     * @throws Exception
445
+     */
446
+    public static function disable($app) {
447
+        // flush
448
+        self::$enabledAppsCache = array();
449
+
450
+        // run uninstall steps
451
+        $appData = OC_App::getAppInfo($app);
452
+        if (!is_null($appData)) {
453
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
454
+        }
455
+
456
+        // emit disable hook - needed anymore ?
457
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
458
+
459
+        // finally disable it
460
+        $appManager = \OC::$server->getAppManager();
461
+        $appManager->disableApp($app);
462
+    }
463
+
464
+    // This is private as well. It simply works, so don't ask for more details
465
+    private static function proceedNavigation($list) {
466
+        usort($list, function($a, $b) {
467
+            if (isset($a['order']) && isset($b['order'])) {
468
+                return ($a['order'] < $b['order']) ? -1 : 1;
469
+            } else if (isset($a['order']) || isset($b['order'])) {
470
+                return isset($a['order']) ? -1 : 1;
471
+            } else {
472
+                return ($a['name'] < $b['name']) ? -1 : 1;
473
+            }
474
+        });
475
+
476
+        $activeAppIndex = -1;
477
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
478
+        foreach ($list as $index => &$navEntry) {
479
+            $navEntry['showInHeader'] = true;
480
+            if ($navEntry['id'] == $activeApp) {
481
+                $navEntry['active'] = true;
482
+                $activeAppIndex = $index;
483
+            } else {
484
+                $navEntry['active'] = false;
485
+            }
486
+        }
487
+        unset($navEntry);
488
+
489
+        if (count($list) <= 8) {
490
+            return $list;
491
+        }
492
+
493
+        $headerIconCount = 7;
494
+        if($activeAppIndex > ($headerIconCount-1)) {
495
+            $active = $list[$activeAppIndex];
496
+            $lastInHeader = $list[$headerIconCount-1];
497
+            $list[$headerIconCount-1] = $active;
498
+            $list[$activeAppIndex] = $lastInHeader;
499
+        }
500
+
501
+        foreach ($list as $index => &$navEntry) {
502
+            if($index >= $headerIconCount) {
503
+                $navEntry['showInHeader'] = false;
504
+            }
505
+        }
506
+
507
+        return $list;
508
+    }
509
+
510
+    public static function proceedAppNavigation($entries) {
511
+        $activeAppIndex = -1;
512
+        $list = self::proceedNavigation($entries);
513
+
514
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
515
+        foreach ($list as $index => &$navEntry) {
516
+            if ($navEntry['id'] == $activeApp) {
517
+                $navEntry['active'] = true;
518
+                $activeAppIndex = $index;
519
+            } else {
520
+                $navEntry['active'] = false;
521
+            }
522
+        }
523
+
524
+
525
+        if (count($list) <= 8) {
526
+            return $list;
527
+        }
528
+
529
+        $headerIconCount = 7;
530
+        // move active item to last position
531
+        if($activeAppIndex > ($headerIconCount-1)) {
532
+            $active = $list[$activeAppIndex];
533
+            $lastInHeader = $list[$headerIconCount-1];
534
+            $list[$headerIconCount-1] = $active;
535
+            $list[$activeAppIndex] = $lastInHeader;
536
+        }
537
+        $list = array_slice($list, 0, $headerIconCount);
538
+
539
+        return $list;
540
+    }
541
+
542
+    /**
543
+     * Get the path where to install apps
544
+     *
545
+     * @return string|false
546
+     */
547
+    public static function getInstallPath() {
548
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
549
+            return false;
550
+        }
551
+
552
+        foreach (OC::$APPSROOTS as $dir) {
553
+            if (isset($dir['writable']) && $dir['writable'] === true) {
554
+                return $dir['path'];
555
+            }
556
+        }
557
+
558
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
559
+        return null;
560
+    }
561
+
562
+
563
+    /**
564
+     * search for an app in all app-directories
565
+     *
566
+     * @param string $appId
567
+     * @return false|string
568
+     */
569
+    public static function findAppInDirectories($appId) {
570
+        $sanitizedAppId = self::cleanAppId($appId);
571
+        if($sanitizedAppId !== $appId) {
572
+            return false;
573
+        }
574
+        static $app_dir = array();
575
+
576
+        if (isset($app_dir[$appId])) {
577
+            return $app_dir[$appId];
578
+        }
579
+
580
+        $possibleApps = array();
581
+        foreach (OC::$APPSROOTS as $dir) {
582
+            if (file_exists($dir['path'] . '/' . $appId)) {
583
+                $possibleApps[] = $dir;
584
+            }
585
+        }
586
+
587
+        if (empty($possibleApps)) {
588
+            return false;
589
+        } elseif (count($possibleApps) === 1) {
590
+            $dir = array_shift($possibleApps);
591
+            $app_dir[$appId] = $dir;
592
+            return $dir;
593
+        } else {
594
+            $versionToLoad = array();
595
+            foreach ($possibleApps as $possibleApp) {
596
+                $version = self::getAppVersionByPath($possibleApp['path']);
597
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
598
+                    $versionToLoad = array(
599
+                        'dir' => $possibleApp,
600
+                        'version' => $version,
601
+                    );
602
+                }
603
+            }
604
+            $app_dir[$appId] = $versionToLoad['dir'];
605
+            return $versionToLoad['dir'];
606
+            //TODO - write test
607
+        }
608
+    }
609
+
610
+    /**
611
+     * Get the directory for the given app.
612
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
613
+     *
614
+     * @param string $appId
615
+     * @return string|false
616
+     */
617
+    public static function getAppPath($appId) {
618
+        if ($appId === null || trim($appId) === '') {
619
+            return false;
620
+        }
621
+
622
+        if (($dir = self::findAppInDirectories($appId)) != false) {
623
+            return $dir['path'] . '/' . $appId;
624
+        }
625
+        return false;
626
+    }
627
+
628
+    /**
629
+     * Get the path for the given app on the access
630
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
631
+     *
632
+     * @param string $appId
633
+     * @return string|false
634
+     */
635
+    public static function getAppWebPath($appId) {
636
+        if (($dir = self::findAppInDirectories($appId)) != false) {
637
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
638
+        }
639
+        return false;
640
+    }
641
+
642
+    /**
643
+     * get the last version of the app from appinfo/info.xml
644
+     *
645
+     * @param string $appId
646
+     * @param bool $useCache
647
+     * @return string
648
+     */
649
+    public static function getAppVersion($appId, $useCache = true) {
650
+        if($useCache && isset(self::$appVersion[$appId])) {
651
+            return self::$appVersion[$appId];
652
+        }
653
+
654
+        $file = self::getAppPath($appId);
655
+        self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
656
+        return self::$appVersion[$appId];
657
+    }
658
+
659
+    /**
660
+     * get app's version based on it's path
661
+     *
662
+     * @param string $path
663
+     * @return string
664
+     */
665
+    public static function getAppVersionByPath($path) {
666
+        $infoFile = $path . '/appinfo/info.xml';
667
+        $appData = self::getAppInfo($infoFile, true);
668
+        return isset($appData['version']) ? $appData['version'] : '';
669
+    }
670
+
671
+
672
+    /**
673
+     * Read all app metadata from the info.xml file
674
+     *
675
+     * @param string $appId id of the app or the path of the info.xml file
676
+     * @param bool $path
677
+     * @param string $lang
678
+     * @return array|null
679
+     * @note all data is read from info.xml, not just pre-defined fields
680
+     */
681
+    public static function getAppInfo($appId, $path = false, $lang = null) {
682
+        if ($path) {
683
+            $file = $appId;
684
+        } else {
685
+            if ($lang === null && isset(self::$appInfo[$appId])) {
686
+                return self::$appInfo[$appId];
687
+            }
688
+            $appPath = self::getAppPath($appId);
689
+            if($appPath === false) {
690
+                return null;
691
+            }
692
+            $file = $appPath . '/appinfo/info.xml';
693
+        }
694
+
695
+        $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
696
+        $data = $parser->parse($file);
697
+
698
+        if (is_array($data)) {
699
+            $data = OC_App::parseAppInfo($data, $lang);
700
+        }
701
+        if(isset($data['ocsid'])) {
702
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
703
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
704
+                $data['ocsid'] = $storedId;
705
+            }
706
+        }
707
+
708
+        if ($lang === null) {
709
+            self::$appInfo[$appId] = $data;
710
+        }
711
+
712
+        return $data;
713
+    }
714
+
715
+    /**
716
+     * Returns the navigation
717
+     *
718
+     * @return array
719
+     *
720
+     * This function returns an array containing all entries added. The
721
+     * entries are sorted by the key 'order' ascending. Additional to the keys
722
+     * given for each app the following keys exist:
723
+     *   - active: boolean, signals if the user is on this navigation entry
724
+     */
725
+    public static function getNavigation() {
726
+        $entries = OC::$server->getNavigationManager()->getAll();
727
+        return self::proceedNavigation($entries);
728
+    }
729
+
730
+    /**
731
+     * Returns the navigation inside the header bar
732
+     *
733
+     * @return array
734
+     *
735
+     * This function returns an array containing all entries added. The
736
+     * entries are sorted by the key 'order' ascending. Additional to the keys
737
+     * given for each app the following keys exist:
738
+     *   - active: boolean, signals if the user is on this navigation entry
739
+     */
740
+    public static function getHeaderNavigation() {
741
+        $entries = OC::$server->getNavigationManager()->getAll();
742
+        return self::proceedAppNavigation($entries);
743
+    }
744
+
745
+    /**
746
+     * Returns the Settings Navigation
747
+     *
748
+     * @return string[]
749
+     *
750
+     * This function returns an array containing all settings pages added. The
751
+     * entries are sorted by the key 'order' ascending.
752
+     */
753
+    public static function getSettingsNavigation() {
754
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
755
+        return self::proceedNavigation($entries);
756
+    }
757
+
758
+    /**
759
+     * get the id of loaded app
760
+     *
761
+     * @return string
762
+     */
763
+    public static function getCurrentApp() {
764
+        $request = \OC::$server->getRequest();
765
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
766
+        $topFolder = substr($script, 0, strpos($script, '/'));
767
+        if (empty($topFolder)) {
768
+            $path_info = $request->getPathInfo();
769
+            if ($path_info) {
770
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
771
+            }
772
+        }
773
+        if ($topFolder == 'apps') {
774
+            $length = strlen($topFolder);
775
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
776
+        } else {
777
+            return $topFolder;
778
+        }
779
+    }
780
+
781
+    /**
782
+     * @param string $type
783
+     * @return array
784
+     */
785
+    public static function getForms($type) {
786
+        $forms = array();
787
+        switch ($type) {
788
+            case 'admin':
789
+                $source = self::$adminForms;
790
+                break;
791
+            case 'personal':
792
+                $source = self::$personalForms;
793
+                break;
794
+            default:
795
+                return array();
796
+        }
797
+        foreach ($source as $form) {
798
+            $forms[] = include $form;
799
+        }
800
+        return $forms;
801
+    }
802
+
803
+    /**
804
+     * register an admin form to be shown
805
+     *
806
+     * @param string $app
807
+     * @param string $page
808
+     */
809
+    public static function registerAdmin($app, $page) {
810
+        self::$adminForms[] = $app . '/' . $page . '.php';
811
+    }
812
+
813
+    /**
814
+     * register a personal form to be shown
815
+     * @param string $app
816
+     * @param string $page
817
+     */
818
+    public static function registerPersonal($app, $page) {
819
+        self::$personalForms[] = $app . '/' . $page . '.php';
820
+    }
821
+
822
+    /**
823
+     * @param array $entry
824
+     */
825
+    public static function registerLogIn(array $entry) {
826
+        self::$altLogin[] = $entry;
827
+    }
828
+
829
+    /**
830
+     * @return array
831
+     */
832
+    public static function getAlternativeLogIns() {
833
+        return self::$altLogin;
834
+    }
835
+
836
+    /**
837
+     * get a list of all apps in the apps folder
838
+     *
839
+     * @return array an array of app names (string IDs)
840
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
841
+     */
842
+    public static function getAllApps() {
843
+
844
+        $apps = array();
845
+
846
+        foreach (OC::$APPSROOTS as $apps_dir) {
847
+            if (!is_readable($apps_dir['path'])) {
848
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
849
+                continue;
850
+            }
851
+            $dh = opendir($apps_dir['path']);
852
+
853
+            if (is_resource($dh)) {
854
+                while (($file = readdir($dh)) !== false) {
855
+
856
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
857
+
858
+                        $apps[] = $file;
859
+                    }
860
+                }
861
+            }
862
+        }
863
+
864
+        return $apps;
865
+    }
866
+
867
+    /**
868
+     * List all apps, this is used in apps.php
869
+     *
870
+     * @return array
871
+     */
872
+    public function listAllApps() {
873
+        $installedApps = OC_App::getAllApps();
874
+
875
+        //we don't want to show configuration for these
876
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
877
+        $appList = array();
878
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
879
+        $urlGenerator = \OC::$server->getURLGenerator();
880
+
881
+        foreach ($installedApps as $app) {
882
+            if (array_search($app, $blacklist) === false) {
883
+
884
+                $info = OC_App::getAppInfo($app, false, $langCode);
885
+                if (!is_array($info)) {
886
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
887
+                    continue;
888
+                }
889
+
890
+                if (!isset($info['name'])) {
891
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
892
+                    continue;
893
+                }
894
+
895
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
896
+                $info['groups'] = null;
897
+                if ($enabled === 'yes') {
898
+                    $active = true;
899
+                } else if ($enabled === 'no') {
900
+                    $active = false;
901
+                } else {
902
+                    $active = true;
903
+                    $info['groups'] = $enabled;
904
+                }
905
+
906
+                $info['active'] = $active;
907
+
908
+                if (self::isShipped($app)) {
909
+                    $info['internal'] = true;
910
+                    $info['level'] = self::officialApp;
911
+                    $info['removable'] = false;
912
+                } else {
913
+                    $info['internal'] = false;
914
+                    $info['removable'] = true;
915
+                }
916
+
917
+                $appPath = self::getAppPath($app);
918
+                if($appPath !== false) {
919
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
920
+                    if (file_exists($appIcon)) {
921
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
922
+                        $info['previewAsIcon'] = true;
923
+                    } else {
924
+                        $appIcon = $appPath . '/img/app.svg';
925
+                        if (file_exists($appIcon)) {
926
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
927
+                            $info['previewAsIcon'] = true;
928
+                        }
929
+                    }
930
+                }
931
+                // fix documentation
932
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
933
+                    foreach ($info['documentation'] as $key => $url) {
934
+                        // If it is not an absolute URL we assume it is a key
935
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
936
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
937
+                            $url = $urlGenerator->linkToDocs($url);
938
+                        }
939
+
940
+                        $info['documentation'][$key] = $url;
941
+                    }
942
+                }
943
+
944
+                $info['version'] = OC_App::getAppVersion($app);
945
+                $appList[] = $info;
946
+            }
947
+        }
948
+
949
+        return $appList;
950
+    }
951
+
952
+    /**
953
+     * Returns the internal app ID or false
954
+     * @param string $ocsID
955
+     * @return string|false
956
+     */
957
+    public static function getInternalAppIdByOcs($ocsID) {
958
+        if(is_numeric($ocsID)) {
959
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
960
+            if(array_search($ocsID, $idArray)) {
961
+                return array_search($ocsID, $idArray);
962
+            }
963
+        }
964
+        return false;
965
+    }
966
+
967
+    public static function shouldUpgrade($app) {
968
+        $versions = self::getAppVersions();
969
+        $currentVersion = OC_App::getAppVersion($app);
970
+        if ($currentVersion && isset($versions[$app])) {
971
+            $installedVersion = $versions[$app];
972
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
973
+                return true;
974
+            }
975
+        }
976
+        return false;
977
+    }
978
+
979
+    /**
980
+     * Adjust the number of version parts of $version1 to match
981
+     * the number of version parts of $version2.
982
+     *
983
+     * @param string $version1 version to adjust
984
+     * @param string $version2 version to take the number of parts from
985
+     * @return string shortened $version1
986
+     */
987
+    private static function adjustVersionParts($version1, $version2) {
988
+        $version1 = explode('.', $version1);
989
+        $version2 = explode('.', $version2);
990
+        // reduce $version1 to match the number of parts in $version2
991
+        while (count($version1) > count($version2)) {
992
+            array_pop($version1);
993
+        }
994
+        // if $version1 does not have enough parts, add some
995
+        while (count($version1) < count($version2)) {
996
+            $version1[] = '0';
997
+        }
998
+        return implode('.', $version1);
999
+    }
1000
+
1001
+    /**
1002
+     * Check whether the current ownCloud version matches the given
1003
+     * application's version requirements.
1004
+     *
1005
+     * The comparison is made based on the number of parts that the
1006
+     * app info version has. For example for ownCloud 6.0.3 if the
1007
+     * app info version is expecting version 6.0, the comparison is
1008
+     * made on the first two parts of the ownCloud version.
1009
+     * This means that it's possible to specify "requiremin" => 6
1010
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
1011
+     *
1012
+     * @param string $ocVersion ownCloud version to check against
1013
+     * @param array $appInfo app info (from xml)
1014
+     *
1015
+     * @return boolean true if compatible, otherwise false
1016
+     */
1017
+    public static function isAppCompatible($ocVersion, $appInfo) {
1018
+        $requireMin = '';
1019
+        $requireMax = '';
1020
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
1021
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
1022
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1023
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1024
+        } else if (isset($appInfo['requiremin'])) {
1025
+            $requireMin = $appInfo['requiremin'];
1026
+        } else if (isset($appInfo['require'])) {
1027
+            $requireMin = $appInfo['require'];
1028
+        }
1029
+
1030
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
1031
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
1032
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1033
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1034
+        } else if (isset($appInfo['requiremax'])) {
1035
+            $requireMax = $appInfo['requiremax'];
1036
+        }
1037
+
1038
+        if (is_array($ocVersion)) {
1039
+            $ocVersion = implode('.', $ocVersion);
1040
+        }
1041
+
1042
+        if (!empty($requireMin)
1043
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1044
+        ) {
1045
+
1046
+            return false;
1047
+        }
1048
+
1049
+        if (!empty($requireMax)
1050
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1051
+        ) {
1052
+            return false;
1053
+        }
1054
+
1055
+        return true;
1056
+    }
1057
+
1058
+    /**
1059
+     * get the installed version of all apps
1060
+     */
1061
+    public static function getAppVersions() {
1062
+        static $versions;
1063
+
1064
+        if(!$versions) {
1065
+            $appConfig = \OC::$server->getAppConfig();
1066
+            $versions = $appConfig->getValues(false, 'installed_version');
1067
+        }
1068
+        return $versions;
1069
+    }
1070
+
1071
+    /**
1072
+     * @param string $app
1073
+     * @param \OCP\IConfig $config
1074
+     * @param \OCP\IL10N $l
1075
+     * @return bool
1076
+     *
1077
+     * @throws Exception if app is not compatible with this version of ownCloud
1078
+     * @throws Exception if no app-name was specified
1079
+     */
1080
+    public function installApp($app,
1081
+                                \OCP\IConfig $config,
1082
+                                \OCP\IL10N $l) {
1083
+        if ($app !== false) {
1084
+            // check if the app is compatible with this version of ownCloud
1085
+            $info = self::getAppInfo($app);
1086
+            if(!is_array($info)) {
1087
+                throw new \Exception(
1088
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1089
+                        [$info['name']]
1090
+                    )
1091
+                );
1092
+            }
1093
+
1094
+            $version = \OCP\Util::getVersion();
1095
+            if (!self::isAppCompatible($version, $info)) {
1096
+                throw new \Exception(
1097
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1098
+                        array($info['name'])
1099
+                    )
1100
+                );
1101
+            }
1102
+
1103
+            // check for required dependencies
1104
+            self::checkAppDependencies($config, $l, $info);
1105
+
1106
+            $config->setAppValue($app, 'enabled', 'yes');
1107
+            if (isset($appData['id'])) {
1108
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1109
+            }
1110
+
1111
+            if(isset($info['settings']) && is_array($info['settings'])) {
1112
+                $appPath = self::getAppPath($app);
1113
+                self::registerAutoloading($app, $appPath);
1114
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1115
+            }
1116
+
1117
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1118
+        } else {
1119
+            if(empty($appName) ) {
1120
+                throw new \Exception($l->t("No app name specified"));
1121
+            } else {
1122
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1123
+            }
1124
+        }
1125
+
1126
+        return $app;
1127
+    }
1128
+
1129
+    /**
1130
+     * update the database for the app and call the update script
1131
+     *
1132
+     * @param string $appId
1133
+     * @return bool
1134
+     */
1135
+    public static function updateApp($appId) {
1136
+        $appPath = self::getAppPath($appId);
1137
+        if($appPath === false) {
1138
+            return false;
1139
+        }
1140
+        $appData = self::getAppInfo($appId);
1141
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1142
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1143
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1144
+        }
1145
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1146
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1147
+        unset(self::$appVersion[$appId]);
1148
+        // run upgrade code
1149
+        if (file_exists($appPath . '/appinfo/update.php')) {
1150
+            self::loadApp($appId);
1151
+            include $appPath . '/appinfo/update.php';
1152
+        }
1153
+        self::setupBackgroundJobs($appData['background-jobs']);
1154
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1155
+            $appPath = self::getAppPath($appId);
1156
+            self::registerAutoloading($appId, $appPath);
1157
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1158
+        }
1159
+
1160
+        //set remote/public handlers
1161
+        if (array_key_exists('ocsid', $appData)) {
1162
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1163
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1164
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1165
+        }
1166
+        foreach ($appData['remote'] as $name => $path) {
1167
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1168
+        }
1169
+        foreach ($appData['public'] as $name => $path) {
1170
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1171
+        }
1172
+
1173
+        self::setAppTypes($appId);
1174
+
1175
+        $version = \OC_App::getAppVersion($appId);
1176
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1177
+
1178
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1179
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1180
+        ));
1181
+
1182
+        return true;
1183
+    }
1184
+
1185
+    /**
1186
+     * @param string $appId
1187
+     * @param string[] $steps
1188
+     * @throws \OC\NeedsUpdateException
1189
+     */
1190
+    public static function executeRepairSteps($appId, array $steps) {
1191
+        if (empty($steps)) {
1192
+            return;
1193
+        }
1194
+        // load the app
1195
+        self::loadApp($appId);
1196
+
1197
+        $dispatcher = OC::$server->getEventDispatcher();
1198
+
1199
+        // load the steps
1200
+        $r = new Repair([], $dispatcher);
1201
+        foreach ($steps as $step) {
1202
+            try {
1203
+                $r->addStep($step);
1204
+            } catch (Exception $ex) {
1205
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1206
+                \OC::$server->getLogger()->logException($ex);
1207
+            }
1208
+        }
1209
+        // run the steps
1210
+        $r->run();
1211
+    }
1212
+
1213
+    public static function setupBackgroundJobs(array $jobs) {
1214
+        $queue = \OC::$server->getJobList();
1215
+        foreach ($jobs as $job) {
1216
+            $queue->add($job);
1217
+        }
1218
+    }
1219
+
1220
+    /**
1221
+     * @param string $appId
1222
+     * @param string[] $steps
1223
+     */
1224
+    private static function setupLiveMigrations($appId, array $steps) {
1225
+        $queue = \OC::$server->getJobList();
1226
+        foreach ($steps as $step) {
1227
+            $queue->add('OC\Migration\BackgroundRepair', [
1228
+                'app' => $appId,
1229
+                'step' => $step]);
1230
+        }
1231
+    }
1232
+
1233
+    /**
1234
+     * @param string $appId
1235
+     * @return \OC\Files\View|false
1236
+     */
1237
+    public static function getStorage($appId) {
1238
+        if (OC_App::isEnabled($appId)) { //sanity check
1239
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1240
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1241
+                if (!$view->file_exists($appId)) {
1242
+                    $view->mkdir($appId);
1243
+                }
1244
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1245
+            } else {
1246
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1247
+                return false;
1248
+            }
1249
+        } else {
1250
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1251
+            return false;
1252
+        }
1253
+    }
1254
+
1255
+    protected static function findBestL10NOption($options, $lang) {
1256
+        $fallback = $similarLangFallback = $englishFallback = false;
1257
+
1258
+        $lang = strtolower($lang);
1259
+        $similarLang = $lang;
1260
+        if (strpos($similarLang, '_')) {
1261
+            // For "de_DE" we want to find "de" and the other way around
1262
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1263
+        }
1264
+
1265
+        foreach ($options as $option) {
1266
+            if (is_array($option)) {
1267
+                if ($fallback === false) {
1268
+                    $fallback = $option['@value'];
1269
+                }
1270
+
1271
+                if (!isset($option['@attributes']['lang'])) {
1272
+                    continue;
1273
+                }
1274
+
1275
+                $attributeLang = strtolower($option['@attributes']['lang']);
1276
+                if ($attributeLang === $lang) {
1277
+                    return $option['@value'];
1278
+                }
1279
+
1280
+                if ($attributeLang === $similarLang) {
1281
+                    $similarLangFallback = $option['@value'];
1282
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1283
+                    if ($similarLangFallback === false) {
1284
+                        $similarLangFallback =  $option['@value'];
1285
+                    }
1286
+                }
1287
+            } else {
1288
+                $englishFallback = $option;
1289
+            }
1290
+        }
1291
+
1292
+        if ($similarLangFallback !== false) {
1293
+            return $similarLangFallback;
1294
+        } else if ($englishFallback !== false) {
1295
+            return $englishFallback;
1296
+        }
1297
+        return (string) $fallback;
1298
+    }
1299
+
1300
+    /**
1301
+     * parses the app data array and enhanced the 'description' value
1302
+     *
1303
+     * @param array $data the app data
1304
+     * @param string $lang
1305
+     * @return array improved app data
1306
+     */
1307
+    public static function parseAppInfo(array $data, $lang = null) {
1308
+
1309
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1310
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1311
+        }
1312
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1313
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1314
+        }
1315
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1316
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1317
+        } else if (isset($data['description']) && is_string($data['description'])) {
1318
+            $data['description'] = trim($data['description']);
1319
+        } else  {
1320
+            $data['description'] = '';
1321
+        }
1322
+
1323
+        return $data;
1324
+    }
1325
+
1326
+    /**
1327
+     * @param \OCP\IConfig $config
1328
+     * @param \OCP\IL10N $l
1329
+     * @param array $info
1330
+     * @throws \Exception
1331
+     */
1332
+    protected static function checkAppDependencies($config, $l, $info) {
1333
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1334
+        $missing = $dependencyAnalyzer->analyze($info);
1335
+        if (!empty($missing)) {
1336
+            $missingMsg = join(PHP_EOL, $missing);
1337
+            throw new \Exception(
1338
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1339
+                    [$info['name'], $missingMsg]
1340
+                )
1341
+            );
1342
+        }
1343
+    }
1344 1344
 }
Please login to merge, or discard this patch.
lib/private/Setup.php 2 patches
Indentation   +483 added lines, -483 removed lines patch added patch discarded remove patch
@@ -48,487 +48,487 @@
 block discarded – undo
48 48
 use OCP\Security\ISecureRandom;
49 49
 
50 50
 class Setup {
51
-	/** @var SystemConfig */
52
-	protected $config;
53
-	/** @var IniGetWrapper */
54
-	protected $iniWrapper;
55
-	/** @var IL10N */
56
-	protected $l10n;
57
-	/** @var Defaults */
58
-	protected $defaults;
59
-	/** @var ILogger */
60
-	protected $logger;
61
-	/** @var ISecureRandom */
62
-	protected $random;
63
-
64
-	/**
65
-	 * @param SystemConfig $config
66
-	 * @param IniGetWrapper $iniWrapper
67
-	 * @param IL10N $l10n
68
-	 * @param Defaults $defaults
69
-	 * @param ILogger $logger
70
-	 * @param ISecureRandom $random
71
-	 */
72
-	public function __construct(SystemConfig $config,
73
-						 IniGetWrapper $iniWrapper,
74
-						 IL10N $l10n,
75
-						 Defaults $defaults,
76
-						 ILogger $logger,
77
-						 ISecureRandom $random
78
-		) {
79
-		$this->config = $config;
80
-		$this->iniWrapper = $iniWrapper;
81
-		$this->l10n = $l10n;
82
-		$this->defaults = $defaults;
83
-		$this->logger = $logger;
84
-		$this->random = $random;
85
-	}
86
-
87
-	static $dbSetupClasses = [
88
-		'mysql' => \OC\Setup\MySQL::class,
89
-		'pgsql' => \OC\Setup\PostgreSQL::class,
90
-		'oci'   => \OC\Setup\OCI::class,
91
-		'sqlite' => \OC\Setup\Sqlite::class,
92
-		'sqlite3' => \OC\Setup\Sqlite::class,
93
-	];
94
-
95
-	/**
96
-	 * Wrapper around the "class_exists" PHP function to be able to mock it
97
-	 * @param string $name
98
-	 * @return bool
99
-	 */
100
-	protected function class_exists($name) {
101
-		return class_exists($name);
102
-	}
103
-
104
-	/**
105
-	 * Wrapper around the "is_callable" PHP function to be able to mock it
106
-	 * @param string $name
107
-	 * @return bool
108
-	 */
109
-	protected function is_callable($name) {
110
-		return is_callable($name);
111
-	}
112
-
113
-	/**
114
-	 * Wrapper around \PDO::getAvailableDrivers
115
-	 *
116
-	 * @return array
117
-	 */
118
-	protected function getAvailableDbDriversForPdo() {
119
-		return \PDO::getAvailableDrivers();
120
-	}
121
-
122
-	/**
123
-	 * Get the available and supported databases of this instance
124
-	 *
125
-	 * @param bool $allowAllDatabases
126
-	 * @return array
127
-	 * @throws Exception
128
-	 */
129
-	public function getSupportedDatabases($allowAllDatabases = false) {
130
-		$availableDatabases = array(
131
-			'sqlite' =>  array(
132
-				'type' => 'pdo',
133
-				'call' => 'sqlite',
134
-				'name' => 'SQLite'
135
-			),
136
-			'mysql' => array(
137
-				'type' => 'pdo',
138
-				'call' => 'mysql',
139
-				'name' => 'MySQL/MariaDB'
140
-			),
141
-			'pgsql' => array(
142
-				'type' => 'pdo',
143
-				'call' => 'pgsql',
144
-				'name' => 'PostgreSQL'
145
-			),
146
-			'oci' => array(
147
-				'type' => 'function',
148
-				'call' => 'oci_connect',
149
-				'name' => 'Oracle'
150
-			)
151
-		);
152
-		if ($allowAllDatabases) {
153
-			$configuredDatabases = array_keys($availableDatabases);
154
-		} else {
155
-			$configuredDatabases = $this->config->getValue('supportedDatabases',
156
-				array('sqlite', 'mysql', 'pgsql'));
157
-		}
158
-		if(!is_array($configuredDatabases)) {
159
-			throw new Exception('Supported databases are not properly configured.');
160
-		}
161
-
162
-		$supportedDatabases = array();
163
-
164
-		foreach($configuredDatabases as $database) {
165
-			if(array_key_exists($database, $availableDatabases)) {
166
-				$working = false;
167
-				$type = $availableDatabases[$database]['type'];
168
-				$call = $availableDatabases[$database]['call'];
169
-
170
-				if ($type === 'function') {
171
-					$working = $this->is_callable($call);
172
-				} elseif($type === 'pdo') {
173
-					$working = in_array($call, $this->getAvailableDbDriversForPdo(), TRUE);
174
-				}
175
-				if($working) {
176
-					$supportedDatabases[$database] = $availableDatabases[$database]['name'];
177
-				}
178
-			}
179
-		}
180
-
181
-		return $supportedDatabases;
182
-	}
183
-
184
-	/**
185
-	 * Gathers system information like database type and does
186
-	 * a few system checks.
187
-	 *
188
-	 * @return array of system info, including an "errors" value
189
-	 * in case of errors/warnings
190
-	 */
191
-	public function getSystemInfo($allowAllDatabases = false) {
192
-		$databases = $this->getSupportedDatabases($allowAllDatabases);
193
-
194
-		$dataDir = $this->config->getValue('datadirectory', \OC::$SERVERROOT.'/data');
195
-
196
-		$errors = array();
197
-
198
-		// Create data directory to test whether the .htaccess works
199
-		// Notice that this is not necessarily the same data directory as the one
200
-		// that will effectively be used.
201
-		if(!file_exists($dataDir)) {
202
-			@mkdir($dataDir);
203
-		}
204
-		$htAccessWorking = true;
205
-		if (is_dir($dataDir) && is_writable($dataDir)) {
206
-			// Protect data directory here, so we can test if the protection is working
207
-			\OC\Setup::protectDataDirectory();
208
-
209
-			try {
210
-				$util = new \OC_Util();
211
-				$htAccessWorking = $util->isHtaccessWorking(\OC::$server->getConfig());
212
-			} catch (\OC\HintException $e) {
213
-				$errors[] = array(
214
-					'error' => $e->getMessage(),
215
-					'hint' => $e->getHint()
216
-				);
217
-				$htAccessWorking = false;
218
-			}
219
-		}
220
-
221
-		if (\OC_Util::runningOnMac()) {
222
-			$errors[] = array(
223
-				'error' => $this->l10n->t(
224
-					'Mac OS X is not supported and %s will not work properly on this platform. ' .
225
-					'Use it at your own risk! ',
226
-					$this->defaults->getName()
227
-				),
228
-				'hint' => $this->l10n->t('For the best results, please consider using a GNU/Linux server instead.')
229
-			);
230
-		}
231
-
232
-		if($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) {
233
-			$errors[] = array(
234
-				'error' => $this->l10n->t(
235
-					'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' .
236
-					'This will lead to problems with files over 4 GB and is highly discouraged.',
237
-					$this->defaults->getName()
238
-				),
239
-				'hint' => $this->l10n->t('Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.')
240
-			);
241
-		}
242
-
243
-		return array(
244
-			'hasSQLite' => isset($databases['sqlite']),
245
-			'hasMySQL' => isset($databases['mysql']),
246
-			'hasPostgreSQL' => isset($databases['pgsql']),
247
-			'hasOracle' => isset($databases['oci']),
248
-			'databases' => $databases,
249
-			'directory' => $dataDir,
250
-			'htaccessWorking' => $htAccessWorking,
251
-			'errors' => $errors,
252
-		);
253
-	}
254
-
255
-	/**
256
-	 * @param $options
257
-	 * @return array
258
-	 */
259
-	public function install($options) {
260
-		$l = $this->l10n;
261
-
262
-		$error = array();
263
-		$dbType = $options['dbtype'];
264
-
265
-		if(empty($options['adminlogin'])) {
266
-			$error[] = $l->t('Set an admin username.');
267
-		}
268
-		if(empty($options['adminpass'])) {
269
-			$error[] = $l->t('Set an admin password.');
270
-		}
271
-		if(empty($options['directory'])) {
272
-			$options['directory'] = \OC::$SERVERROOT."/data";
273
-		}
274
-
275
-		if (!isset(self::$dbSetupClasses[$dbType])) {
276
-			$dbType = 'sqlite';
277
-		}
278
-
279
-		$username = htmlspecialchars_decode($options['adminlogin']);
280
-		$password = htmlspecialchars_decode($options['adminpass']);
281
-		$dataDir = htmlspecialchars_decode($options['directory']);
282
-
283
-		$class = self::$dbSetupClasses[$dbType];
284
-		/** @var \OC\Setup\AbstractDatabase $dbSetup */
285
-		$dbSetup = new $class($l, 'db_structure.xml', $this->config,
286
-			$this->logger, $this->random);
287
-		$error = array_merge($error, $dbSetup->validate($options));
288
-
289
-		// validate the data directory
290
-		if (
291
-			(!is_dir($dataDir) and !mkdir($dataDir)) or
292
-			!is_writable($dataDir)
293
-		) {
294
-			$error[] = $l->t("Can't create or write into the data directory %s", array($dataDir));
295
-		}
296
-
297
-		if(count($error) != 0) {
298
-			return $error;
299
-		}
300
-
301
-		$request = \OC::$server->getRequest();
302
-
303
-		//no errors, good
304
-		if(isset($options['trusted_domains'])
305
-		    && is_array($options['trusted_domains'])) {
306
-			$trustedDomains = $options['trusted_domains'];
307
-		} else {
308
-			$trustedDomains = [$request->getInsecureServerHost()];
309
-		}
310
-
311
-		//use sqlite3 when available, otherwise sqlite2 will be used.
312
-		if($dbType=='sqlite' and class_exists('SQLite3')) {
313
-			$dbType='sqlite3';
314
-		}
315
-
316
-		//generate a random salt that is used to salt the local user passwords
317
-		$salt = $this->random->generate(30);
318
-		// generate a secret
319
-		$secret = $this->random->generate(48);
320
-
321
-		//write the config file
322
-		$this->config->setValues([
323
-			'passwordsalt'		=> $salt,
324
-			'secret'			=> $secret,
325
-			'trusted_domains'	=> $trustedDomains,
326
-			'datadirectory'		=> $dataDir,
327
-			'overwrite.cli.url'	=> $request->getServerProtocol() . '://' . $request->getInsecureServerHost() . \OC::$WEBROOT,
328
-			'dbtype'			=> $dbType,
329
-			'version'			=> implode('.', \OCP\Util::getVersion()),
330
-		]);
331
-
332
-		try {
333
-			$dbSetup->initialize($options);
334
-			$dbSetup->setupDatabase($username);
335
-		} catch (\OC\DatabaseSetupException $e) {
336
-			$error[] = array(
337
-				'error' => $e->getMessage(),
338
-				'hint' => $e->getHint()
339
-			);
340
-			return($error);
341
-		} catch (Exception $e) {
342
-			$error[] = array(
343
-				'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
344
-				'hint' => ''
345
-			);
346
-			return($error);
347
-		}
348
-
349
-		//create the user and group
350
-		$user =  null;
351
-		try {
352
-			$user = \OC::$server->getUserManager()->createUser($username, $password);
353
-			if (!$user) {
354
-				$error[] = "User <$username> could not be created.";
355
-			}
356
-		} catch(Exception $exception) {
357
-			$error[] = $exception->getMessage();
358
-		}
359
-
360
-		if(count($error) == 0) {
361
-			$config = \OC::$server->getConfig();
362
-			$config->setAppValue('core', 'installedat', microtime(true));
363
-			$config->setAppValue('core', 'lastupdatedat', microtime(true));
364
-			$config->setAppValue('core', 'vendor', $this->getVendor());
365
-
366
-			$group =\OC::$server->getGroupManager()->createGroup('admin');
367
-			$group->addUser($user);
368
-
369
-			// Install shipped apps and specified app bundles
370
-			Installer::installShippedApps();
371
-			$installer = new Installer(
372
-				\OC::$server->getAppFetcher(),
373
-				\OC::$server->getAppManager(),
374
-				\OC::$server->getHTTPClientService(),
375
-				\OC::$server->getTempManager(),
376
-				\OC::$server->getLogger(),
377
-				\OC::$server->getConfig()
378
-			);
379
-			foreach($options['bundle'] as $bundle) {
380
-				try {
381
-					$bundle = (new BundleFetcher(\OC::$server->getL10N('lib')))->getBundleByIdentifier($bundle);
382
-					$installer->installAppBundle($bundle);
383
-				} catch (Exception $e) {
384
-					// TODO: Catch error. This is just for debugging :-)
385
-					throw $e;
386
-				}
387
-			}
388
-
389
-			// create empty file in data dir, so we can later find
390
-			// out that this is indeed an ownCloud data directory
391
-			file_put_contents($config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
392
-
393
-			// Update .htaccess files
394
-			Setup::updateHtaccess();
395
-			Setup::protectDataDirectory();
396
-
397
-			self::installBackgroundJobs();
398
-
399
-			//and we are done
400
-			$config->setSystemValue('installed', true);
401
-
402
-			// Create a session token for the newly created user
403
-			// The token provider requires a working db, so it's not injected on setup
404
-			/* @var $userSession User\Session */
405
-			$userSession = \OC::$server->getUserSession();
406
-			$defaultTokenProvider = \OC::$server->query('OC\Authentication\Token\DefaultTokenProvider');
407
-			$userSession->setTokenProvider($defaultTokenProvider);
408
-			$userSession->login($username, $password);
409
-			$userSession->createSessionToken($request, $userSession->getUser()->getUID(), $username, $password);
410
-		}
411
-
412
-		return $error;
413
-	}
414
-
415
-	public static function installBackgroundJobs() {
416
-		\OC::$server->getJobList()->add('\OC\Authentication\Token\DefaultTokenCleanupJob');
417
-	}
418
-
419
-	/**
420
-	 * @return string Absolute path to htaccess
421
-	 */
422
-	private function pathToHtaccess() {
423
-		return \OC::$SERVERROOT.'/.htaccess';
424
-	}
425
-
426
-	/**
427
-	 * Append the correct ErrorDocument path for Apache hosts
428
-	 * @return bool True when success, False otherwise
429
-	 */
430
-	public static function updateHtaccess() {
431
-		$config = \OC::$server->getSystemConfig();
432
-
433
-		// For CLI read the value from overwrite.cli.url
434
-		if(\OC::$CLI) {
435
-			$webRoot = $config->getValue('overwrite.cli.url', '');
436
-			if($webRoot === '') {
437
-				return false;
438
-			}
439
-			$webRoot = parse_url($webRoot, PHP_URL_PATH);
440
-			$webRoot = rtrim($webRoot, '/');
441
-		} else {
442
-			$webRoot = !empty(\OC::$WEBROOT) ? \OC::$WEBROOT : '/';
443
-		}
444
-
445
-		$setupHelper = new \OC\Setup($config, \OC::$server->getIniWrapper(),
446
-			\OC::$server->getL10N('lib'), \OC::$server->query(Defaults::class), \OC::$server->getLogger(),
447
-			\OC::$server->getSecureRandom());
448
-
449
-		$htaccessContent = file_get_contents($setupHelper->pathToHtaccess());
450
-		$content = "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####\n";
451
-		$htaccessContent = explode($content, $htaccessContent, 2)[0];
452
-
453
-		//custom 403 error page
454
-		$content.= "\nErrorDocument 403 ".$webRoot."/core/templates/403.php";
455
-
456
-		//custom 404 error page
457
-		$content.= "\nErrorDocument 404 ".$webRoot."/core/templates/404.php";
458
-
459
-		// Add rewrite rules if the RewriteBase is configured
460
-		$rewriteBase = $config->getValue('htaccess.RewriteBase', '');
461
-		if($rewriteBase !== '') {
462
-			$content .= "\n<IfModule mod_rewrite.c>";
463
-			$content .= "\n  Options -MultiViews";
464
-			$content .= "\n  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]";
465
-			$content .= "\n  RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]";
466
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !\\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$";
467
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$";
468
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/remote.php";
469
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/public.php";
470
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/cron.php";
471
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php";
472
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/status.php";
473
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php";
474
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php";
475
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/robots.txt";
476
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/updater/";
477
-			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs-provider/";
478
-			$content .= "\n  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*";
479
-			$content .= "\n  RewriteRule . index.php [PT,E=PATH_INFO:$1]";
480
-			$content .= "\n  RewriteBase " . $rewriteBase;
481
-			$content .= "\n  <IfModule mod_env.c>";
482
-			$content .= "\n    SetEnv front_controller_active true";
483
-			$content .= "\n    <IfModule mod_dir.c>";
484
-			$content .= "\n      DirectorySlash off";
485
-			$content .= "\n    </IfModule>";
486
-			$content .= "\n  </IfModule>";
487
-			$content .= "\n</IfModule>";
488
-		}
489
-
490
-		if ($content !== '') {
491
-			//suppress errors in case we don't have permissions for it
492
-			return (bool) @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content . "\n");
493
-		}
494
-
495
-		return false;
496
-	}
497
-
498
-	public static function protectDataDirectory() {
499
-		//Require all denied
500
-		$now =  date('Y-m-d H:i:s');
501
-		$content = "# Generated by Nextcloud on $now\n";
502
-		$content.= "# line below if for Apache 2.4\n";
503
-		$content.= "<ifModule mod_authz_core.c>\n";
504
-		$content.= "Require all denied\n";
505
-		$content.= "</ifModule>\n\n";
506
-		$content.= "# line below if for Apache 2.2\n";
507
-		$content.= "<ifModule !mod_authz_core.c>\n";
508
-		$content.= "deny from all\n";
509
-		$content.= "Satisfy All\n";
510
-		$content.= "</ifModule>\n\n";
511
-		$content.= "# section for Apache 2.2 and 2.4\n";
512
-		$content.= "<ifModule mod_autoindex.c>\n";
513
-		$content.= "IndexIgnore *\n";
514
-		$content.= "</ifModule>\n";
515
-
516
-		$baseDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
517
-		file_put_contents($baseDir . '/.htaccess', $content);
518
-		file_put_contents($baseDir . '/index.html', '');
519
-	}
520
-
521
-	/**
522
-	 * Return vendor from which this version was published
523
-	 *
524
-	 * @return string Get the vendor
525
-	 *
526
-	 * Copy of \OC\Updater::getVendor()
527
-	 */
528
-	private function getVendor() {
529
-		// this should really be a JSON file
530
-		require \OC::$SERVERROOT . '/version.php';
531
-		/** @var string $vendor */
532
-		return (string) $vendor;
533
-	}
51
+    /** @var SystemConfig */
52
+    protected $config;
53
+    /** @var IniGetWrapper */
54
+    protected $iniWrapper;
55
+    /** @var IL10N */
56
+    protected $l10n;
57
+    /** @var Defaults */
58
+    protected $defaults;
59
+    /** @var ILogger */
60
+    protected $logger;
61
+    /** @var ISecureRandom */
62
+    protected $random;
63
+
64
+    /**
65
+     * @param SystemConfig $config
66
+     * @param IniGetWrapper $iniWrapper
67
+     * @param IL10N $l10n
68
+     * @param Defaults $defaults
69
+     * @param ILogger $logger
70
+     * @param ISecureRandom $random
71
+     */
72
+    public function __construct(SystemConfig $config,
73
+                            IniGetWrapper $iniWrapper,
74
+                            IL10N $l10n,
75
+                            Defaults $defaults,
76
+                            ILogger $logger,
77
+                            ISecureRandom $random
78
+        ) {
79
+        $this->config = $config;
80
+        $this->iniWrapper = $iniWrapper;
81
+        $this->l10n = $l10n;
82
+        $this->defaults = $defaults;
83
+        $this->logger = $logger;
84
+        $this->random = $random;
85
+    }
86
+
87
+    static $dbSetupClasses = [
88
+        'mysql' => \OC\Setup\MySQL::class,
89
+        'pgsql' => \OC\Setup\PostgreSQL::class,
90
+        'oci'   => \OC\Setup\OCI::class,
91
+        'sqlite' => \OC\Setup\Sqlite::class,
92
+        'sqlite3' => \OC\Setup\Sqlite::class,
93
+    ];
94
+
95
+    /**
96
+     * Wrapper around the "class_exists" PHP function to be able to mock it
97
+     * @param string $name
98
+     * @return bool
99
+     */
100
+    protected function class_exists($name) {
101
+        return class_exists($name);
102
+    }
103
+
104
+    /**
105
+     * Wrapper around the "is_callable" PHP function to be able to mock it
106
+     * @param string $name
107
+     * @return bool
108
+     */
109
+    protected function is_callable($name) {
110
+        return is_callable($name);
111
+    }
112
+
113
+    /**
114
+     * Wrapper around \PDO::getAvailableDrivers
115
+     *
116
+     * @return array
117
+     */
118
+    protected function getAvailableDbDriversForPdo() {
119
+        return \PDO::getAvailableDrivers();
120
+    }
121
+
122
+    /**
123
+     * Get the available and supported databases of this instance
124
+     *
125
+     * @param bool $allowAllDatabases
126
+     * @return array
127
+     * @throws Exception
128
+     */
129
+    public function getSupportedDatabases($allowAllDatabases = false) {
130
+        $availableDatabases = array(
131
+            'sqlite' =>  array(
132
+                'type' => 'pdo',
133
+                'call' => 'sqlite',
134
+                'name' => 'SQLite'
135
+            ),
136
+            'mysql' => array(
137
+                'type' => 'pdo',
138
+                'call' => 'mysql',
139
+                'name' => 'MySQL/MariaDB'
140
+            ),
141
+            'pgsql' => array(
142
+                'type' => 'pdo',
143
+                'call' => 'pgsql',
144
+                'name' => 'PostgreSQL'
145
+            ),
146
+            'oci' => array(
147
+                'type' => 'function',
148
+                'call' => 'oci_connect',
149
+                'name' => 'Oracle'
150
+            )
151
+        );
152
+        if ($allowAllDatabases) {
153
+            $configuredDatabases = array_keys($availableDatabases);
154
+        } else {
155
+            $configuredDatabases = $this->config->getValue('supportedDatabases',
156
+                array('sqlite', 'mysql', 'pgsql'));
157
+        }
158
+        if(!is_array($configuredDatabases)) {
159
+            throw new Exception('Supported databases are not properly configured.');
160
+        }
161
+
162
+        $supportedDatabases = array();
163
+
164
+        foreach($configuredDatabases as $database) {
165
+            if(array_key_exists($database, $availableDatabases)) {
166
+                $working = false;
167
+                $type = $availableDatabases[$database]['type'];
168
+                $call = $availableDatabases[$database]['call'];
169
+
170
+                if ($type === 'function') {
171
+                    $working = $this->is_callable($call);
172
+                } elseif($type === 'pdo') {
173
+                    $working = in_array($call, $this->getAvailableDbDriversForPdo(), TRUE);
174
+                }
175
+                if($working) {
176
+                    $supportedDatabases[$database] = $availableDatabases[$database]['name'];
177
+                }
178
+            }
179
+        }
180
+
181
+        return $supportedDatabases;
182
+    }
183
+
184
+    /**
185
+     * Gathers system information like database type and does
186
+     * a few system checks.
187
+     *
188
+     * @return array of system info, including an "errors" value
189
+     * in case of errors/warnings
190
+     */
191
+    public function getSystemInfo($allowAllDatabases = false) {
192
+        $databases = $this->getSupportedDatabases($allowAllDatabases);
193
+
194
+        $dataDir = $this->config->getValue('datadirectory', \OC::$SERVERROOT.'/data');
195
+
196
+        $errors = array();
197
+
198
+        // Create data directory to test whether the .htaccess works
199
+        // Notice that this is not necessarily the same data directory as the one
200
+        // that will effectively be used.
201
+        if(!file_exists($dataDir)) {
202
+            @mkdir($dataDir);
203
+        }
204
+        $htAccessWorking = true;
205
+        if (is_dir($dataDir) && is_writable($dataDir)) {
206
+            // Protect data directory here, so we can test if the protection is working
207
+            \OC\Setup::protectDataDirectory();
208
+
209
+            try {
210
+                $util = new \OC_Util();
211
+                $htAccessWorking = $util->isHtaccessWorking(\OC::$server->getConfig());
212
+            } catch (\OC\HintException $e) {
213
+                $errors[] = array(
214
+                    'error' => $e->getMessage(),
215
+                    'hint' => $e->getHint()
216
+                );
217
+                $htAccessWorking = false;
218
+            }
219
+        }
220
+
221
+        if (\OC_Util::runningOnMac()) {
222
+            $errors[] = array(
223
+                'error' => $this->l10n->t(
224
+                    'Mac OS X is not supported and %s will not work properly on this platform. ' .
225
+                    'Use it at your own risk! ',
226
+                    $this->defaults->getName()
227
+                ),
228
+                'hint' => $this->l10n->t('For the best results, please consider using a GNU/Linux server instead.')
229
+            );
230
+        }
231
+
232
+        if($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) {
233
+            $errors[] = array(
234
+                'error' => $this->l10n->t(
235
+                    'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' .
236
+                    'This will lead to problems with files over 4 GB and is highly discouraged.',
237
+                    $this->defaults->getName()
238
+                ),
239
+                'hint' => $this->l10n->t('Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.')
240
+            );
241
+        }
242
+
243
+        return array(
244
+            'hasSQLite' => isset($databases['sqlite']),
245
+            'hasMySQL' => isset($databases['mysql']),
246
+            'hasPostgreSQL' => isset($databases['pgsql']),
247
+            'hasOracle' => isset($databases['oci']),
248
+            'databases' => $databases,
249
+            'directory' => $dataDir,
250
+            'htaccessWorking' => $htAccessWorking,
251
+            'errors' => $errors,
252
+        );
253
+    }
254
+
255
+    /**
256
+     * @param $options
257
+     * @return array
258
+     */
259
+    public function install($options) {
260
+        $l = $this->l10n;
261
+
262
+        $error = array();
263
+        $dbType = $options['dbtype'];
264
+
265
+        if(empty($options['adminlogin'])) {
266
+            $error[] = $l->t('Set an admin username.');
267
+        }
268
+        if(empty($options['adminpass'])) {
269
+            $error[] = $l->t('Set an admin password.');
270
+        }
271
+        if(empty($options['directory'])) {
272
+            $options['directory'] = \OC::$SERVERROOT."/data";
273
+        }
274
+
275
+        if (!isset(self::$dbSetupClasses[$dbType])) {
276
+            $dbType = 'sqlite';
277
+        }
278
+
279
+        $username = htmlspecialchars_decode($options['adminlogin']);
280
+        $password = htmlspecialchars_decode($options['adminpass']);
281
+        $dataDir = htmlspecialchars_decode($options['directory']);
282
+
283
+        $class = self::$dbSetupClasses[$dbType];
284
+        /** @var \OC\Setup\AbstractDatabase $dbSetup */
285
+        $dbSetup = new $class($l, 'db_structure.xml', $this->config,
286
+            $this->logger, $this->random);
287
+        $error = array_merge($error, $dbSetup->validate($options));
288
+
289
+        // validate the data directory
290
+        if (
291
+            (!is_dir($dataDir) and !mkdir($dataDir)) or
292
+            !is_writable($dataDir)
293
+        ) {
294
+            $error[] = $l->t("Can't create or write into the data directory %s", array($dataDir));
295
+        }
296
+
297
+        if(count($error) != 0) {
298
+            return $error;
299
+        }
300
+
301
+        $request = \OC::$server->getRequest();
302
+
303
+        //no errors, good
304
+        if(isset($options['trusted_domains'])
305
+            && is_array($options['trusted_domains'])) {
306
+            $trustedDomains = $options['trusted_domains'];
307
+        } else {
308
+            $trustedDomains = [$request->getInsecureServerHost()];
309
+        }
310
+
311
+        //use sqlite3 when available, otherwise sqlite2 will be used.
312
+        if($dbType=='sqlite' and class_exists('SQLite3')) {
313
+            $dbType='sqlite3';
314
+        }
315
+
316
+        //generate a random salt that is used to salt the local user passwords
317
+        $salt = $this->random->generate(30);
318
+        // generate a secret
319
+        $secret = $this->random->generate(48);
320
+
321
+        //write the config file
322
+        $this->config->setValues([
323
+            'passwordsalt'		=> $salt,
324
+            'secret'			=> $secret,
325
+            'trusted_domains'	=> $trustedDomains,
326
+            'datadirectory'		=> $dataDir,
327
+            'overwrite.cli.url'	=> $request->getServerProtocol() . '://' . $request->getInsecureServerHost() . \OC::$WEBROOT,
328
+            'dbtype'			=> $dbType,
329
+            'version'			=> implode('.', \OCP\Util::getVersion()),
330
+        ]);
331
+
332
+        try {
333
+            $dbSetup->initialize($options);
334
+            $dbSetup->setupDatabase($username);
335
+        } catch (\OC\DatabaseSetupException $e) {
336
+            $error[] = array(
337
+                'error' => $e->getMessage(),
338
+                'hint' => $e->getHint()
339
+            );
340
+            return($error);
341
+        } catch (Exception $e) {
342
+            $error[] = array(
343
+                'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
344
+                'hint' => ''
345
+            );
346
+            return($error);
347
+        }
348
+
349
+        //create the user and group
350
+        $user =  null;
351
+        try {
352
+            $user = \OC::$server->getUserManager()->createUser($username, $password);
353
+            if (!$user) {
354
+                $error[] = "User <$username> could not be created.";
355
+            }
356
+        } catch(Exception $exception) {
357
+            $error[] = $exception->getMessage();
358
+        }
359
+
360
+        if(count($error) == 0) {
361
+            $config = \OC::$server->getConfig();
362
+            $config->setAppValue('core', 'installedat', microtime(true));
363
+            $config->setAppValue('core', 'lastupdatedat', microtime(true));
364
+            $config->setAppValue('core', 'vendor', $this->getVendor());
365
+
366
+            $group =\OC::$server->getGroupManager()->createGroup('admin');
367
+            $group->addUser($user);
368
+
369
+            // Install shipped apps and specified app bundles
370
+            Installer::installShippedApps();
371
+            $installer = new Installer(
372
+                \OC::$server->getAppFetcher(),
373
+                \OC::$server->getAppManager(),
374
+                \OC::$server->getHTTPClientService(),
375
+                \OC::$server->getTempManager(),
376
+                \OC::$server->getLogger(),
377
+                \OC::$server->getConfig()
378
+            );
379
+            foreach($options['bundle'] as $bundle) {
380
+                try {
381
+                    $bundle = (new BundleFetcher(\OC::$server->getL10N('lib')))->getBundleByIdentifier($bundle);
382
+                    $installer->installAppBundle($bundle);
383
+                } catch (Exception $e) {
384
+                    // TODO: Catch error. This is just for debugging :-)
385
+                    throw $e;
386
+                }
387
+            }
388
+
389
+            // create empty file in data dir, so we can later find
390
+            // out that this is indeed an ownCloud data directory
391
+            file_put_contents($config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
392
+
393
+            // Update .htaccess files
394
+            Setup::updateHtaccess();
395
+            Setup::protectDataDirectory();
396
+
397
+            self::installBackgroundJobs();
398
+
399
+            //and we are done
400
+            $config->setSystemValue('installed', true);
401
+
402
+            // Create a session token for the newly created user
403
+            // The token provider requires a working db, so it's not injected on setup
404
+            /* @var $userSession User\Session */
405
+            $userSession = \OC::$server->getUserSession();
406
+            $defaultTokenProvider = \OC::$server->query('OC\Authentication\Token\DefaultTokenProvider');
407
+            $userSession->setTokenProvider($defaultTokenProvider);
408
+            $userSession->login($username, $password);
409
+            $userSession->createSessionToken($request, $userSession->getUser()->getUID(), $username, $password);
410
+        }
411
+
412
+        return $error;
413
+    }
414
+
415
+    public static function installBackgroundJobs() {
416
+        \OC::$server->getJobList()->add('\OC\Authentication\Token\DefaultTokenCleanupJob');
417
+    }
418
+
419
+    /**
420
+     * @return string Absolute path to htaccess
421
+     */
422
+    private function pathToHtaccess() {
423
+        return \OC::$SERVERROOT.'/.htaccess';
424
+    }
425
+
426
+    /**
427
+     * Append the correct ErrorDocument path for Apache hosts
428
+     * @return bool True when success, False otherwise
429
+     */
430
+    public static function updateHtaccess() {
431
+        $config = \OC::$server->getSystemConfig();
432
+
433
+        // For CLI read the value from overwrite.cli.url
434
+        if(\OC::$CLI) {
435
+            $webRoot = $config->getValue('overwrite.cli.url', '');
436
+            if($webRoot === '') {
437
+                return false;
438
+            }
439
+            $webRoot = parse_url($webRoot, PHP_URL_PATH);
440
+            $webRoot = rtrim($webRoot, '/');
441
+        } else {
442
+            $webRoot = !empty(\OC::$WEBROOT) ? \OC::$WEBROOT : '/';
443
+        }
444
+
445
+        $setupHelper = new \OC\Setup($config, \OC::$server->getIniWrapper(),
446
+            \OC::$server->getL10N('lib'), \OC::$server->query(Defaults::class), \OC::$server->getLogger(),
447
+            \OC::$server->getSecureRandom());
448
+
449
+        $htaccessContent = file_get_contents($setupHelper->pathToHtaccess());
450
+        $content = "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####\n";
451
+        $htaccessContent = explode($content, $htaccessContent, 2)[0];
452
+
453
+        //custom 403 error page
454
+        $content.= "\nErrorDocument 403 ".$webRoot."/core/templates/403.php";
455
+
456
+        //custom 404 error page
457
+        $content.= "\nErrorDocument 404 ".$webRoot."/core/templates/404.php";
458
+
459
+        // Add rewrite rules if the RewriteBase is configured
460
+        $rewriteBase = $config->getValue('htaccess.RewriteBase', '');
461
+        if($rewriteBase !== '') {
462
+            $content .= "\n<IfModule mod_rewrite.c>";
463
+            $content .= "\n  Options -MultiViews";
464
+            $content .= "\n  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]";
465
+            $content .= "\n  RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]";
466
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !\\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$";
467
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$";
468
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/remote.php";
469
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/public.php";
470
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/cron.php";
471
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php";
472
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/status.php";
473
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php";
474
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php";
475
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/robots.txt";
476
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/updater/";
477
+            $content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs-provider/";
478
+            $content .= "\n  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*";
479
+            $content .= "\n  RewriteRule . index.php [PT,E=PATH_INFO:$1]";
480
+            $content .= "\n  RewriteBase " . $rewriteBase;
481
+            $content .= "\n  <IfModule mod_env.c>";
482
+            $content .= "\n    SetEnv front_controller_active true";
483
+            $content .= "\n    <IfModule mod_dir.c>";
484
+            $content .= "\n      DirectorySlash off";
485
+            $content .= "\n    </IfModule>";
486
+            $content .= "\n  </IfModule>";
487
+            $content .= "\n</IfModule>";
488
+        }
489
+
490
+        if ($content !== '') {
491
+            //suppress errors in case we don't have permissions for it
492
+            return (bool) @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content . "\n");
493
+        }
494
+
495
+        return false;
496
+    }
497
+
498
+    public static function protectDataDirectory() {
499
+        //Require all denied
500
+        $now =  date('Y-m-d H:i:s');
501
+        $content = "# Generated by Nextcloud on $now\n";
502
+        $content.= "# line below if for Apache 2.4\n";
503
+        $content.= "<ifModule mod_authz_core.c>\n";
504
+        $content.= "Require all denied\n";
505
+        $content.= "</ifModule>\n\n";
506
+        $content.= "# line below if for Apache 2.2\n";
507
+        $content.= "<ifModule !mod_authz_core.c>\n";
508
+        $content.= "deny from all\n";
509
+        $content.= "Satisfy All\n";
510
+        $content.= "</ifModule>\n\n";
511
+        $content.= "# section for Apache 2.2 and 2.4\n";
512
+        $content.= "<ifModule mod_autoindex.c>\n";
513
+        $content.= "IndexIgnore *\n";
514
+        $content.= "</ifModule>\n";
515
+
516
+        $baseDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
517
+        file_put_contents($baseDir . '/.htaccess', $content);
518
+        file_put_contents($baseDir . '/index.html', '');
519
+    }
520
+
521
+    /**
522
+     * Return vendor from which this version was published
523
+     *
524
+     * @return string Get the vendor
525
+     *
526
+     * Copy of \OC\Updater::getVendor()
527
+     */
528
+    private function getVendor() {
529
+        // this should really be a JSON file
530
+        require \OC::$SERVERROOT . '/version.php';
531
+        /** @var string $vendor */
532
+        return (string) $vendor;
533
+    }
534 534
 }
Please login to merge, or discard this patch.
Spacing   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -155,24 +155,24 @@  discard block
 block discarded – undo
155 155
 			$configuredDatabases = $this->config->getValue('supportedDatabases',
156 156
 				array('sqlite', 'mysql', 'pgsql'));
157 157
 		}
158
-		if(!is_array($configuredDatabases)) {
158
+		if (!is_array($configuredDatabases)) {
159 159
 			throw new Exception('Supported databases are not properly configured.');
160 160
 		}
161 161
 
162 162
 		$supportedDatabases = array();
163 163
 
164
-		foreach($configuredDatabases as $database) {
165
-			if(array_key_exists($database, $availableDatabases)) {
164
+		foreach ($configuredDatabases as $database) {
165
+			if (array_key_exists($database, $availableDatabases)) {
166 166
 				$working = false;
167 167
 				$type = $availableDatabases[$database]['type'];
168 168
 				$call = $availableDatabases[$database]['call'];
169 169
 
170 170
 				if ($type === 'function') {
171 171
 					$working = $this->is_callable($call);
172
-				} elseif($type === 'pdo') {
172
+				} elseif ($type === 'pdo') {
173 173
 					$working = in_array($call, $this->getAvailableDbDriversForPdo(), TRUE);
174 174
 				}
175
-				if($working) {
175
+				if ($working) {
176 176
 					$supportedDatabases[$database] = $availableDatabases[$database]['name'];
177 177
 				}
178 178
 			}
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 		// Create data directory to test whether the .htaccess works
199 199
 		// Notice that this is not necessarily the same data directory as the one
200 200
 		// that will effectively be used.
201
-		if(!file_exists($dataDir)) {
201
+		if (!file_exists($dataDir)) {
202 202
 			@mkdir($dataDir);
203 203
 		}
204 204
 		$htAccessWorking = true;
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
 		if (\OC_Util::runningOnMac()) {
222 222
 			$errors[] = array(
223 223
 				'error' => $this->l10n->t(
224
-					'Mac OS X is not supported and %s will not work properly on this platform. ' .
224
+					'Mac OS X is not supported and %s will not work properly on this platform. '.
225 225
 					'Use it at your own risk! ',
226 226
 					$this->defaults->getName()
227 227
 				),
@@ -229,10 +229,10 @@  discard block
 block discarded – undo
229 229
 			);
230 230
 		}
231 231
 
232
-		if($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) {
232
+		if ($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) {
233 233
 			$errors[] = array(
234 234
 				'error' => $this->l10n->t(
235
-					'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' .
235
+					'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. '.
236 236
 					'This will lead to problems with files over 4 GB and is highly discouraged.',
237 237
 					$this->defaults->getName()
238 238
 				),
@@ -262,13 +262,13 @@  discard block
 block discarded – undo
262 262
 		$error = array();
263 263
 		$dbType = $options['dbtype'];
264 264
 
265
-		if(empty($options['adminlogin'])) {
265
+		if (empty($options['adminlogin'])) {
266 266
 			$error[] = $l->t('Set an admin username.');
267 267
 		}
268
-		if(empty($options['adminpass'])) {
268
+		if (empty($options['adminpass'])) {
269 269
 			$error[] = $l->t('Set an admin password.');
270 270
 		}
271
-		if(empty($options['directory'])) {
271
+		if (empty($options['directory'])) {
272 272
 			$options['directory'] = \OC::$SERVERROOT."/data";
273 273
 		}
274 274
 
@@ -294,14 +294,14 @@  discard block
 block discarded – undo
294 294
 			$error[] = $l->t("Can't create or write into the data directory %s", array($dataDir));
295 295
 		}
296 296
 
297
-		if(count($error) != 0) {
297
+		if (count($error) != 0) {
298 298
 			return $error;
299 299
 		}
300 300
 
301 301
 		$request = \OC::$server->getRequest();
302 302
 
303 303
 		//no errors, good
304
-		if(isset($options['trusted_domains'])
304
+		if (isset($options['trusted_domains'])
305 305
 		    && is_array($options['trusted_domains'])) {
306 306
 			$trustedDomains = $options['trusted_domains'];
307 307
 		} else {
@@ -309,8 +309,8 @@  discard block
 block discarded – undo
309 309
 		}
310 310
 
311 311
 		//use sqlite3 when available, otherwise sqlite2 will be used.
312
-		if($dbType=='sqlite' and class_exists('SQLite3')) {
313
-			$dbType='sqlite3';
312
+		if ($dbType == 'sqlite' and class_exists('SQLite3')) {
313
+			$dbType = 'sqlite3';
314 314
 		}
315 315
 
316 316
 		//generate a random salt that is used to salt the local user passwords
@@ -324,7 +324,7 @@  discard block
 block discarded – undo
324 324
 			'secret'			=> $secret,
325 325
 			'trusted_domains'	=> $trustedDomains,
326 326
 			'datadirectory'		=> $dataDir,
327
-			'overwrite.cli.url'	=> $request->getServerProtocol() . '://' . $request->getInsecureServerHost() . \OC::$WEBROOT,
327
+			'overwrite.cli.url'	=> $request->getServerProtocol().'://'.$request->getInsecureServerHost().\OC::$WEBROOT,
328 328
 			'dbtype'			=> $dbType,
329 329
 			'version'			=> implode('.', \OCP\Util::getVersion()),
330 330
 		]);
@@ -340,30 +340,30 @@  discard block
 block discarded – undo
340 340
 			return($error);
341 341
 		} catch (Exception $e) {
342 342
 			$error[] = array(
343
-				'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
343
+				'error' => 'Error while trying to create admin user: '.$e->getMessage(),
344 344
 				'hint' => ''
345 345
 			);
346 346
 			return($error);
347 347
 		}
348 348
 
349 349
 		//create the user and group
350
-		$user =  null;
350
+		$user = null;
351 351
 		try {
352 352
 			$user = \OC::$server->getUserManager()->createUser($username, $password);
353 353
 			if (!$user) {
354 354
 				$error[] = "User <$username> could not be created.";
355 355
 			}
356
-		} catch(Exception $exception) {
356
+		} catch (Exception $exception) {
357 357
 			$error[] = $exception->getMessage();
358 358
 		}
359 359
 
360
-		if(count($error) == 0) {
360
+		if (count($error) == 0) {
361 361
 			$config = \OC::$server->getConfig();
362 362
 			$config->setAppValue('core', 'installedat', microtime(true));
363 363
 			$config->setAppValue('core', 'lastupdatedat', microtime(true));
364 364
 			$config->setAppValue('core', 'vendor', $this->getVendor());
365 365
 
366
-			$group =\OC::$server->getGroupManager()->createGroup('admin');
366
+			$group = \OC::$server->getGroupManager()->createGroup('admin');
367 367
 			$group->addUser($user);
368 368
 
369 369
 			// Install shipped apps and specified app bundles
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 				\OC::$server->getLogger(),
377 377
 				\OC::$server->getConfig()
378 378
 			);
379
-			foreach($options['bundle'] as $bundle) {
379
+			foreach ($options['bundle'] as $bundle) {
380 380
 				try {
381 381
 					$bundle = (new BundleFetcher(\OC::$server->getL10N('lib')))->getBundleByIdentifier($bundle);
382 382
 					$installer->installAppBundle($bundle);
@@ -431,9 +431,9 @@  discard block
 block discarded – undo
431 431
 		$config = \OC::$server->getSystemConfig();
432 432
 
433 433
 		// For CLI read the value from overwrite.cli.url
434
-		if(\OC::$CLI) {
434
+		if (\OC::$CLI) {
435 435
 			$webRoot = $config->getValue('overwrite.cli.url', '');
436
-			if($webRoot === '') {
436
+			if ($webRoot === '') {
437 437
 				return false;
438 438
 			}
439 439
 			$webRoot = parse_url($webRoot, PHP_URL_PATH);
@@ -451,14 +451,14 @@  discard block
 block discarded – undo
451 451
 		$htaccessContent = explode($content, $htaccessContent, 2)[0];
452 452
 
453 453
 		//custom 403 error page
454
-		$content.= "\nErrorDocument 403 ".$webRoot."/core/templates/403.php";
454
+		$content .= "\nErrorDocument 403 ".$webRoot."/core/templates/403.php";
455 455
 
456 456
 		//custom 404 error page
457
-		$content.= "\nErrorDocument 404 ".$webRoot."/core/templates/404.php";
457
+		$content .= "\nErrorDocument 404 ".$webRoot."/core/templates/404.php";
458 458
 
459 459
 		// Add rewrite rules if the RewriteBase is configured
460 460
 		$rewriteBase = $config->getValue('htaccess.RewriteBase', '');
461
-		if($rewriteBase !== '') {
461
+		if ($rewriteBase !== '') {
462 462
 			$content .= "\n<IfModule mod_rewrite.c>";
463 463
 			$content .= "\n  Options -MultiViews";
464 464
 			$content .= "\n  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]";
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 			$content .= "\n  RewriteCond %{REQUEST_FILENAME} !/ocs-provider/";
478 478
 			$content .= "\n  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*";
479 479
 			$content .= "\n  RewriteRule . index.php [PT,E=PATH_INFO:$1]";
480
-			$content .= "\n  RewriteBase " . $rewriteBase;
480
+			$content .= "\n  RewriteBase ".$rewriteBase;
481 481
 			$content .= "\n  <IfModule mod_env.c>";
482 482
 			$content .= "\n    SetEnv front_controller_active true";
483 483
 			$content .= "\n    <IfModule mod_dir.c>";
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
 
490 490
 		if ($content !== '') {
491 491
 			//suppress errors in case we don't have permissions for it
492
-			return (bool) @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content . "\n");
492
+			return (bool) @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content."\n");
493 493
 		}
494 494
 
495 495
 		return false;
@@ -497,25 +497,25 @@  discard block
 block discarded – undo
497 497
 
498 498
 	public static function protectDataDirectory() {
499 499
 		//Require all denied
500
-		$now =  date('Y-m-d H:i:s');
500
+		$now = date('Y-m-d H:i:s');
501 501
 		$content = "# Generated by Nextcloud on $now\n";
502
-		$content.= "# line below if for Apache 2.4\n";
503
-		$content.= "<ifModule mod_authz_core.c>\n";
504
-		$content.= "Require all denied\n";
505
-		$content.= "</ifModule>\n\n";
506
-		$content.= "# line below if for Apache 2.2\n";
507
-		$content.= "<ifModule !mod_authz_core.c>\n";
508
-		$content.= "deny from all\n";
509
-		$content.= "Satisfy All\n";
510
-		$content.= "</ifModule>\n\n";
511
-		$content.= "# section for Apache 2.2 and 2.4\n";
512
-		$content.= "<ifModule mod_autoindex.c>\n";
513
-		$content.= "IndexIgnore *\n";
514
-		$content.= "</ifModule>\n";
515
-
516
-		$baseDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
517
-		file_put_contents($baseDir . '/.htaccess', $content);
518
-		file_put_contents($baseDir . '/index.html', '');
502
+		$content .= "# line below if for Apache 2.4\n";
503
+		$content .= "<ifModule mod_authz_core.c>\n";
504
+		$content .= "Require all denied\n";
505
+		$content .= "</ifModule>\n\n";
506
+		$content .= "# line below if for Apache 2.2\n";
507
+		$content .= "<ifModule !mod_authz_core.c>\n";
508
+		$content .= "deny from all\n";
509
+		$content .= "Satisfy All\n";
510
+		$content .= "</ifModule>\n\n";
511
+		$content .= "# section for Apache 2.2 and 2.4\n";
512
+		$content .= "<ifModule mod_autoindex.c>\n";
513
+		$content .= "IndexIgnore *\n";
514
+		$content .= "</ifModule>\n";
515
+
516
+		$baseDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data');
517
+		file_put_contents($baseDir.'/.htaccess', $content);
518
+		file_put_contents($baseDir.'/index.html', '');
519 519
 	}
520 520
 
521 521
 	/**
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
 	 */
528 528
 	private function getVendor() {
529 529
 		// this should really be a JSON file
530
-		require \OC::$SERVERROOT . '/version.php';
530
+		require \OC::$SERVERROOT.'/version.php';
531 531
 		/** @var string $vendor */
532 532
 		return (string) $vendor;
533 533
 	}
Please login to merge, or discard this patch.
lib/private/App/AppStore/Bundles/BundleFetcher.php 2 patches
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -24,41 +24,41 @@
 block discarded – undo
24 24
 use OCP\IL10N;
25 25
 
26 26
 class BundleFetcher {
27
-	/** @var IL10N */
28
-	private $l10n;
27
+    /** @var IL10N */
28
+    private $l10n;
29 29
 
30
-	/**
31
-	 * @param IL10N $l10n
32
-	 */
33
-	public function __construct(IL10N $l10n) {
34
-		$this->l10n = $l10n;
35
-	}
30
+    /**
31
+     * @param IL10N $l10n
32
+     */
33
+    public function __construct(IL10N $l10n) {
34
+        $this->l10n = $l10n;
35
+    }
36 36
 
37
-	/**
38
-	 * @return Bundle[]
39
-	 */
40
-	public function getBundles() {
41
-		return [
42
-			new EnterpriseBundle($this->l10n),
43
-			new GroupwareBundle($this->l10n),
44
-		];
45
-	}
37
+    /**
38
+     * @return Bundle[]
39
+     */
40
+    public function getBundles() {
41
+        return [
42
+            new EnterpriseBundle($this->l10n),
43
+            new GroupwareBundle($this->l10n),
44
+        ];
45
+    }
46 46
 
47
-	/**
48
-	 * Get the bundle with the specified identifier
49
-	 *
50
-	 * @param string $identifier
51
-	 * @return Bundle
52
-	 * @throws \BadMethodCallException If the bundle does not exist
53
-	 */
54
-	public function getBundleByIdentifier($identifier) {
55
-		$bundles = $this->getBundles();
56
-		foreach($bundles as $bundle) {
57
-			if($bundle->getIdentifier() === $identifier) {
58
-				return $bundle;
59
-			}
60
-		}
47
+    /**
48
+     * Get the bundle with the specified identifier
49
+     *
50
+     * @param string $identifier
51
+     * @return Bundle
52
+     * @throws \BadMethodCallException If the bundle does not exist
53
+     */
54
+    public function getBundleByIdentifier($identifier) {
55
+        $bundles = $this->getBundles();
56
+        foreach($bundles as $bundle) {
57
+            if($bundle->getIdentifier() === $identifier) {
58
+                return $bundle;
59
+            }
60
+        }
61 61
 
62
-		throw new \BadMethodCallException('Bundle with specified identifier does not exist');
63
-	}
62
+        throw new \BadMethodCallException('Bundle with specified identifier does not exist');
63
+    }
64 64
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -53,8 +53,8 @@
 block discarded – undo
53 53
 	 */
54 54
 	public function getBundleByIdentifier($identifier) {
55 55
 		$bundles = $this->getBundles();
56
-		foreach($bundles as $bundle) {
57
-			if($bundle->getIdentifier() === $identifier) {
56
+		foreach ($bundles as $bundle) {
57
+			if ($bundle->getIdentifier() === $identifier) {
58 58
 				return $bundle;
59 59
 			}
60 60
 		}
Please login to merge, or discard this patch.
lib/private/App/AppStore/Bundles/EnterpriseBundle.php 2 patches
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -23,28 +23,28 @@
 block discarded – undo
23 23
 
24 24
 class EnterpriseBundle extends Bundle {
25 25
 
26
-	/**
27
-	 * {@inheritDoc}
28
-	 */
29
-	public function getName() {
30
-		return (string)$this->l10n->t('Enterprise bundle');
31
-	}
26
+    /**
27
+     * {@inheritDoc}
28
+     */
29
+    public function getName() {
30
+        return (string)$this->l10n->t('Enterprise bundle');
31
+    }
32 32
 
33
-	/**
34
-	 * {@inheritDoc}
35
-	 */
36
-	public function getDescription() {
37
-		return (string)$this->l10n->t('Apps for the Enterprise.');
38
-	}
33
+    /**
34
+     * {@inheritDoc}
35
+     */
36
+    public function getDescription() {
37
+        return (string)$this->l10n->t('Apps for the Enterprise.');
38
+    }
39 39
 
40
-	/**
41
-	 * {@inheritDoc}
42
-	 */
43
-	public function getAppIdentifiers() {
44
-		return [
45
-			'admin_audit',
46
-			'user_ldap',
47
-		];
48
-	}
40
+    /**
41
+     * {@inheritDoc}
42
+     */
43
+    public function getAppIdentifiers() {
44
+        return [
45
+            'admin_audit',
46
+            'user_ldap',
47
+        ];
48
+    }
49 49
 
50 50
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -27,14 +27,14 @@
 block discarded – undo
27 27
 	 * {@inheritDoc}
28 28
 	 */
29 29
 	public function getName() {
30
-		return (string)$this->l10n->t('Enterprise bundle');
30
+		return (string) $this->l10n->t('Enterprise bundle');
31 31
 	}
32 32
 
33 33
 	/**
34 34
 	 * {@inheritDoc}
35 35
 	 */
36 36
 	public function getDescription() {
37
-		return (string)$this->l10n->t('Apps for the Enterprise.');
37
+		return (string) $this->l10n->t('Apps for the Enterprise.');
38 38
 	}
39 39
 
40 40
 	/**
Please login to merge, or discard this patch.
lib/private/App/AppStore/Bundles/GroupwareBundle.php 2 patches
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -23,28 +23,28 @@
 block discarded – undo
23 23
 
24 24
 class GroupwareBundle extends Bundle {
25 25
 
26
-	/**
27
-	 * {@inheritDoc}
28
-	 */
29
-	public function getName() {
30
-		return (string)$this->l10n->t('Groupware bundle');
31
-	}
26
+    /**
27
+     * {@inheritDoc}
28
+     */
29
+    public function getName() {
30
+        return (string)$this->l10n->t('Groupware bundle');
31
+    }
32 32
 
33
-	/**
34
-	 * {@inheritDoc}
35
-	 */
36
-	public function getDescription() {
37
-		return (string)$this->l10n->t('Apps for groupware functionalities.');
38
-	}
33
+    /**
34
+     * {@inheritDoc}
35
+     */
36
+    public function getDescription() {
37
+        return (string)$this->l10n->t('Apps for groupware functionalities.');
38
+    }
39 39
 
40
-	/**
41
-	 * {@inheritDoc}
42
-	 */
43
-	public function getAppIdentifiers() {
44
-		return [
45
-			'calendar',
46
-			'contacts',
47
-		];
48
-	}
40
+    /**
41
+     * {@inheritDoc}
42
+     */
43
+    public function getAppIdentifiers() {
44
+        return [
45
+            'calendar',
46
+            'contacts',
47
+        ];
48
+    }
49 49
 
50 50
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -27,14 +27,14 @@
 block discarded – undo
27 27
 	 * {@inheritDoc}
28 28
 	 */
29 29
 	public function getName() {
30
-		return (string)$this->l10n->t('Groupware bundle');
30
+		return (string) $this->l10n->t('Groupware bundle');
31 31
 	}
32 32
 
33 33
 	/**
34 34
 	 * {@inheritDoc}
35 35
 	 */
36 36
 	public function getDescription() {
37
-		return (string)$this->l10n->t('Apps for groupware functionalities.');
37
+		return (string) $this->l10n->t('Apps for groupware functionalities.');
38 38
 	}
39 39
 
40 40
 	/**
Please login to merge, or discard this patch.