Completed
Pull Request — master (#5833)
by Tobia
14:48
created
settings/ajax/disableapp.php 2 patches
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -26,19 +26,19 @@
 block discarded – undo
26 26
 
27 27
 $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm');
28 28
 if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay
29
-	$l = \OC::$server->getL10N('core');
30
-	OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
31
-	exit();
29
+    $l = \OC::$server->getL10N('core');
30
+    OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
31
+    exit();
32 32
 }
33 33
 
34 34
 if (!array_key_exists('appid', $_POST)) {
35
-	OC_JSON::error();
36
-	exit;
35
+    OC_JSON::error();
36
+    exit;
37 37
 }
38 38
 
39 39
 $appIds = (array)$_POST['appid'];
40 40
 foreach($appIds as $appId) {
41
-	$appId = OC_App::cleanAppId($appId);
42
-	\OC::$server->getAppManager()->disableApp($appId);
41
+    $appId = OC_App::cleanAppId($appId);
42
+    \OC::$server->getAppManager()->disableApp($appId);
43 43
 }
44 44
 OC_JSON::success();
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
 $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm');
28 28
 if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay
29 29
 	$l = \OC::$server->getL10N('core');
30
-	OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
30
+	OC_JSON::error(array('data' => array('message' => $l->t('Password confirmation is required'))));
31 31
 	exit();
32 32
 }
33 33
 
@@ -36,8 +36,8 @@  discard block
 block discarded – undo
36 36
 	exit;
37 37
 }
38 38
 
39
-$appIds = (array)$_POST['appid'];
40
-foreach($appIds as $appId) {
39
+$appIds = (array) $_POST['appid'];
40
+foreach ($appIds as $appId) {
41 41
 	$appId = OC_App::cleanAppId($appId);
42 42
 	\OC::$server->getAppManager()->disableApp($appId);
43 43
 }
Please login to merge, or discard this patch.
lib/base.php 2 patches
Indentation   +990 added lines, -990 removed lines patch added patch discarded remove patch
@@ -67,996 +67,996 @@
 block discarded – undo
67 67
  * OC_autoload!
68 68
  */
69 69
 class OC {
70
-	/**
71
-	 * Associative array for autoloading. classname => filename
72
-	 */
73
-	public static $CLASSPATH = array();
74
-	/**
75
-	 * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
76
-	 */
77
-	public static $SERVERROOT = '';
78
-	/**
79
-	 * the current request path relative to the Nextcloud root (e.g. files/index.php)
80
-	 */
81
-	private static $SUBURI = '';
82
-	/**
83
-	 * the Nextcloud root path for http requests (e.g. nextcloud/)
84
-	 */
85
-	public static $WEBROOT = '';
86
-	/**
87
-	 * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
88
-	 * web path in 'url'
89
-	 */
90
-	public static $APPSROOTS = array();
91
-
92
-	/**
93
-	 * @var string
94
-	 */
95
-	public static $configDir;
96
-
97
-	/**
98
-	 * requested app
99
-	 */
100
-	public static $REQUESTEDAPP = '';
101
-
102
-	/**
103
-	 * check if Nextcloud runs in cli mode
104
-	 */
105
-	public static $CLI = false;
106
-
107
-	/**
108
-	 * @var \OC\Autoloader $loader
109
-	 */
110
-	public static $loader = null;
111
-
112
-	/** @var \Composer\Autoload\ClassLoader $composerAutoloader */
113
-	public static $composerAutoloader = null;
114
-
115
-	/**
116
-	 * @var \OC\Server
117
-	 */
118
-	public static $server = null;
119
-
120
-	/**
121
-	 * @var \OC\Config
122
-	 */
123
-	private static $config = null;
124
-
125
-	/**
126
-	 * @throws \RuntimeException when the 3rdparty directory is missing or
127
-	 * the app path list is empty or contains an invalid path
128
-	 */
129
-	public static function initPaths() {
130
-		if(defined('PHPUNIT_CONFIG_DIR')) {
131
-			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
132
-		} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
133
-			self::$configDir = OC::$SERVERROOT . '/tests/config/';
134
-		} elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
-			self::$configDir = rtrim($dir, '/') . '/';
136
-		} else {
137
-			self::$configDir = OC::$SERVERROOT . '/config/';
138
-		}
139
-		self::$config = new \OC\Config(self::$configDir);
140
-
141
-		OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
142
-		/**
143
-		 * FIXME: The following lines are required because we can't yet instantiate
144
-		 *        \OC::$server->getRequest() since \OC::$server does not yet exist.
145
-		 */
146
-		$params = [
147
-			'server' => [
148
-				'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
149
-				'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
150
-			],
151
-		];
152
-		$fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
153
-		$scriptName = $fakeRequest->getScriptName();
154
-		if (substr($scriptName, -1) == '/') {
155
-			$scriptName .= 'index.php';
156
-			//make sure suburi follows the same rules as scriptName
157
-			if (substr(OC::$SUBURI, -9) != 'index.php') {
158
-				if (substr(OC::$SUBURI, -1) != '/') {
159
-					OC::$SUBURI = OC::$SUBURI . '/';
160
-				}
161
-				OC::$SUBURI = OC::$SUBURI . 'index.php';
162
-			}
163
-		}
164
-
165
-
166
-		if (OC::$CLI) {
167
-			OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
168
-		} else {
169
-			if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
170
-				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
171
-
172
-				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
173
-					OC::$WEBROOT = '/' . OC::$WEBROOT;
174
-				}
175
-			} else {
176
-				// The scriptName is not ending with OC::$SUBURI
177
-				// This most likely means that we are calling from CLI.
178
-				// However some cron jobs still need to generate
179
-				// a web URL, so we use overwritewebroot as a fallback.
180
-				OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
181
-			}
182
-
183
-			// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
184
-			// slash which is required by URL generation.
185
-			if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
186
-					substr($_SERVER['REQUEST_URI'], -1) !== '/') {
187
-				header('Location: '.\OC::$WEBROOT.'/');
188
-				exit();
189
-			}
190
-		}
191
-
192
-		// search the apps folder
193
-		$config_paths = self::$config->getValue('apps_paths', array());
194
-		if (!empty($config_paths)) {
195
-			foreach ($config_paths as $paths) {
196
-				if (isset($paths['url']) && isset($paths['path'])) {
197
-					$paths['url'] = rtrim($paths['url'], '/');
198
-					$paths['path'] = rtrim($paths['path'], '/');
199
-					OC::$APPSROOTS[] = $paths;
200
-				}
201
-			}
202
-		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
203
-			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
204
-		} elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
205
-			OC::$APPSROOTS[] = array(
206
-				'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
207
-				'url' => '/apps',
208
-				'writable' => true
209
-			);
210
-		}
211
-
212
-		if (empty(OC::$APPSROOTS)) {
213
-			throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
214
-				. ' or the folder above. You can also configure the location in the config.php file.');
215
-		}
216
-		$paths = array();
217
-		foreach (OC::$APPSROOTS as $path) {
218
-			$paths[] = $path['path'];
219
-			if (!is_dir($path['path'])) {
220
-				throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
221
-					. ' Nextcloud folder or the folder above. You can also configure the location in the'
222
-					. ' config.php file.', $path['path']));
223
-			}
224
-		}
225
-
226
-		// set the right include path
227
-		set_include_path(
228
-			implode(PATH_SEPARATOR, $paths)
229
-		);
230
-	}
231
-
232
-	public static function checkConfig() {
233
-		$l = \OC::$server->getL10N('lib');
234
-
235
-		// Create config if it does not already exist
236
-		$configFilePath = self::$configDir .'/config.php';
237
-		if(!file_exists($configFilePath)) {
238
-			@touch($configFilePath);
239
-		}
240
-
241
-		// Check if config is writable
242
-		$configFileWritable = is_writable($configFilePath);
243
-		if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
244
-			|| !$configFileWritable && \OCP\Util::needUpgrade()) {
245
-
246
-			$urlGenerator = \OC::$server->getURLGenerator();
247
-
248
-			if (self::$CLI) {
249
-				echo $l->t('Cannot write into "config" directory!')."\n";
250
-				echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
251
-				echo "\n";
252
-				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
253
-				exit;
254
-			} else {
255
-				OC_Template::printErrorPage(
256
-					$l->t('Cannot write into "config" directory!'),
257
-					$l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
258
-					 [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
259
-				);
260
-			}
261
-		}
262
-	}
263
-
264
-	public static function checkInstalled() {
265
-		if (defined('OC_CONSOLE')) {
266
-			return;
267
-		}
268
-		// Redirect to installer if not installed
269
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
270
-			if (OC::$CLI) {
271
-				throw new Exception('Not installed');
272
-			} else {
273
-				$url = OC::$WEBROOT . '/index.php';
274
-				header('Location: ' . $url);
275
-			}
276
-			exit();
277
-		}
278
-	}
279
-
280
-	public static function checkMaintenanceMode() {
281
-		// Allow ajax update script to execute without being stopped
282
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
283
-			// send http status 503
284
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
285
-			header('Status: 503 Service Temporarily Unavailable');
286
-			header('Retry-After: 120');
287
-
288
-			// render error page
289
-			$template = new OC_Template('', 'update.user', 'guest');
290
-			OC_Util::addScript('maintenance-check');
291
-			OC_Util::addStyle('core', 'guest');
292
-			$template->printPage();
293
-			die();
294
-		}
295
-	}
296
-
297
-	/**
298
-	 * Prints the upgrade page
299
-	 *
300
-	 * @param \OC\SystemConfig $systemConfig
301
-	 */
302
-	private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
303
-		$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
304
-		$tooBig = false;
305
-		if (!$disableWebUpdater) {
306
-			$apps = \OC::$server->getAppManager();
307
-			if ($apps->isInstalled('user_ldap')) {
308
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
309
-
310
-				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
311
-					->from('ldap_user_mapping')
312
-					->execute();
313
-				$row = $result->fetch();
314
-				$result->closeCursor();
315
-
316
-				$tooBig = ($row['user_count'] > 50);
317
-			}
318
-			if (!$tooBig && $apps->isInstalled('user_saml')) {
319
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
320
-
321
-				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
322
-					->from('user_saml_users')
323
-					->execute();
324
-				$row = $result->fetch();
325
-				$result->closeCursor();
326
-
327
-				$tooBig = ($row['user_count'] > 50);
328
-			}
329
-			if (!$tooBig) {
330
-				// count users
331
-				$stats = \OC::$server->getUserManager()->countUsers();
332
-				$totalUsers = array_sum($stats);
333
-				$tooBig = ($totalUsers > 50);
334
-			}
335
-		}
336
-		$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
337
-			$_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
338
-
339
-		if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
340
-			// send http status 503
341
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
342
-			header('Status: 503 Service Temporarily Unavailable');
343
-			header('Retry-After: 120');
344
-
345
-			// render error page
346
-			$template = new OC_Template('', 'update.use-cli', 'guest');
347
-			$template->assign('productName', 'nextcloud'); // for now
348
-			$template->assign('version', OC_Util::getVersionString());
349
-			$template->assign('tooBig', $tooBig);
350
-
351
-			$template->printPage();
352
-			die();
353
-		}
354
-
355
-		// check whether this is a core update or apps update
356
-		$installedVersion = $systemConfig->getValue('version', '0.0.0');
357
-		$currentVersion = implode('.', \OCP\Util::getVersion());
358
-
359
-		// if not a core upgrade, then it's apps upgrade
360
-		$isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
361
-
362
-		$oldTheme = $systemConfig->getValue('theme');
363
-		$systemConfig->setValue('theme', '');
364
-		OC_Util::addScript('config'); // needed for web root
365
-		OC_Util::addScript('update');
366
-
367
-		/** @var \OC\App\AppManager $appManager */
368
-		$appManager = \OC::$server->getAppManager();
369
-
370
-		$tmpl = new OC_Template('', 'update.admin', 'guest');
371
-		$tmpl->assign('version', OC_Util::getVersionString());
372
-		$tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
373
-
374
-		// get third party apps
375
-		$ocVersion = \OCP\Util::getVersion();
376
-		$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
377
-		$incompatibleShippedApps = [];
378
-		foreach ($incompatibleApps as $appInfo) {
379
-			if ($appManager->isShipped($appInfo['id'])) {
380
-				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
381
-			}
382
-		}
383
-
384
-		if (!empty($incompatibleShippedApps)) {
385
-			$l = \OC::$server->getL10N('core');
386
-			$hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
387
-			throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
388
-		}
389
-
390
-		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
391
-		$tmpl->assign('incompatibleAppsList', $incompatibleApps);
392
-		$tmpl->assign('productName', 'Nextcloud'); // for now
393
-		$tmpl->assign('oldTheme', $oldTheme);
394
-		$tmpl->printPage();
395
-	}
396
-
397
-	public static function initSession() {
398
-		if(self::$server->getRequest()->getServerProtocol() === 'https') {
399
-			ini_set('session.cookie_secure', true);
400
-		}
401
-
402
-		// prevents javascript from accessing php session cookies
403
-		ini_set('session.cookie_httponly', 'true');
404
-
405
-		// set the cookie path to the Nextcloud directory
406
-		$cookie_path = OC::$WEBROOT ? : '/';
407
-		ini_set('session.cookie_path', $cookie_path);
408
-
409
-		// Let the session name be changed in the initSession Hook
410
-		$sessionName = OC_Util::getInstanceId();
411
-
412
-		try {
413
-			// Allow session apps to create a custom session object
414
-			$useCustomSession = false;
415
-			$session = self::$server->getSession();
416
-			OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
417
-			if (!$useCustomSession) {
418
-				// set the session name to the instance id - which is unique
419
-				$session = new \OC\Session\Internal($sessionName);
420
-			}
421
-
422
-			$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
423
-			$session = $cryptoWrapper->wrapSession($session);
424
-			self::$server->setSession($session);
425
-
426
-			// if session can't be started break with http 500 error
427
-		} catch (Exception $e) {
428
-			\OCP\Util::logException('base', $e);
429
-			//show the user a detailed error page
430
-			OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
431
-			OC_Template::printExceptionErrorPage($e);
432
-			die();
433
-		}
434
-
435
-		$sessionLifeTime = self::getSessionLifeTime();
436
-
437
-		// session timeout
438
-		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
439
-			if (isset($_COOKIE[session_name()])) {
440
-				setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
441
-			}
442
-			\OC::$server->getUserSession()->logout();
443
-		}
444
-
445
-		$session->set('LAST_ACTIVITY', time());
446
-	}
447
-
448
-	/**
449
-	 * @return string
450
-	 */
451
-	private static function getSessionLifeTime() {
452
-		return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
453
-	}
454
-
455
-	public static function loadAppClassPaths() {
456
-		foreach (OC_App::getEnabledApps() as $app) {
457
-			$appPath = OC_App::getAppPath($app);
458
-			if ($appPath === false) {
459
-				continue;
460
-			}
461
-
462
-			$file = $appPath . '/appinfo/classpath.php';
463
-			if (file_exists($file)) {
464
-				require_once $file;
465
-			}
466
-		}
467
-	}
468
-
469
-	/**
470
-	 * Try to set some values to the required Nextcloud default
471
-	 */
472
-	public static function setRequiredIniValues() {
473
-		@ini_set('default_charset', 'UTF-8');
474
-		@ini_set('gd.jpeg_ignore_warning', '1');
475
-	}
476
-
477
-	/**
478
-	 * Send the same site cookies
479
-	 */
480
-	private static function sendSameSiteCookies() {
481
-		$cookieParams = session_get_cookie_params();
482
-		$secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
483
-		$policies = [
484
-			'lax',
485
-			'strict',
486
-		];
487
-
488
-		// Append __Host to the cookie if it meets the requirements
489
-		$cookiePrefix = '';
490
-		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
491
-			$cookiePrefix = '__Host-';
492
-		}
493
-
494
-		foreach($policies as $policy) {
495
-			header(
496
-				sprintf(
497
-					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
498
-					$cookiePrefix,
499
-					$policy,
500
-					$cookieParams['path'],
501
-					$policy
502
-				),
503
-				false
504
-			);
505
-		}
506
-	}
507
-
508
-	/**
509
-	 * Same Site cookie to further mitigate CSRF attacks. This cookie has to
510
-	 * be set in every request if cookies are sent to add a second level of
511
-	 * defense against CSRF.
512
-	 *
513
-	 * If the cookie is not sent this will set the cookie and reload the page.
514
-	 * We use an additional cookie since we want to protect logout CSRF and
515
-	 * also we can't directly interfere with PHP's session mechanism.
516
-	 */
517
-	private static function performSameSiteCookieProtection() {
518
-		$request = \OC::$server->getRequest();
519
-
520
-		// Some user agents are notorious and don't really properly follow HTTP
521
-		// specifications. For those, have an automated opt-out. Since the protection
522
-		// for remote.php is applied in base.php as starting point we need to opt out
523
-		// here.
524
-		$incompatibleUserAgents = [
525
-			// OS X Finder
526
-			'/^WebDAVFS/',
527
-		];
528
-		if($request->isUserAgent($incompatibleUserAgents)) {
529
-			return;
530
-		}
531
-
532
-		if(count($_COOKIE) > 0) {
533
-			$requestUri = $request->getScriptName();
534
-			$processingScript = explode('/', $requestUri);
535
-			$processingScript = $processingScript[count($processingScript)-1];
536
-
537
-			// index.php routes are handled in the middleware
538
-			if($processingScript === 'index.php') {
539
-				return;
540
-			}
541
-
542
-			// All other endpoints require the lax and the strict cookie
543
-			if(!$request->passesStrictCookieCheck()) {
544
-				self::sendSameSiteCookies();
545
-				// Debug mode gets access to the resources without strict cookie
546
-				// due to the fact that the SabreDAV browser also lives there.
547
-				if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
548
-					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
549
-					exit();
550
-				}
551
-			}
552
-		} elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
553
-			self::sendSameSiteCookies();
554
-		}
555
-	}
556
-
557
-	public static function init() {
558
-		// calculate the root directories
559
-		OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
560
-
561
-		// register autoloader
562
-		$loaderStart = microtime(true);
563
-		require_once __DIR__ . '/autoloader.php';
564
-		self::$loader = new \OC\Autoloader([
565
-			OC::$SERVERROOT . '/lib/private/legacy',
566
-		]);
567
-		if (defined('PHPUNIT_RUN')) {
568
-			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
569
-		}
570
-		spl_autoload_register(array(self::$loader, 'load'));
571
-		$loaderEnd = microtime(true);
572
-
573
-		self::$CLI = (php_sapi_name() == 'cli');
574
-
575
-		// Add default composer PSR-4 autoloader
576
-		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
577
-
578
-		try {
579
-			self::initPaths();
580
-			// setup 3rdparty autoloader
581
-			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
582
-			if (!file_exists($vendorAutoLoad)) {
583
-				throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
584
-			}
585
-			require_once $vendorAutoLoad;
586
-
587
-		} catch (\RuntimeException $e) {
588
-			if (!self::$CLI) {
589
-				$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
590
-				$protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
591
-				header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
592
-			}
593
-			// we can't use the template error page here, because this needs the
594
-			// DI container which isn't available yet
595
-			print($e->getMessage());
596
-			exit();
597
-		}
598
-
599
-		// setup the basic server
600
-		self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
601
-		\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
602
-		\OC::$server->getEventLogger()->start('boot', 'Initialize');
603
-
604
-		// Don't display errors and log them
605
-		error_reporting(E_ALL | E_STRICT);
606
-		@ini_set('display_errors', '0');
607
-		@ini_set('log_errors', '1');
608
-
609
-		if(!date_default_timezone_set('UTC')) {
610
-			throw new \RuntimeException('Could not set timezone to UTC');
611
-		}
612
-
613
-		//try to configure php to enable big file uploads.
614
-		//this doesn´t work always depending on the webserver and php configuration.
615
-		//Let´s try to overwrite some defaults anyway
616
-
617
-		//try to set the maximum execution time to 60min
618
-		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
619
-			@set_time_limit(3600);
620
-		}
621
-		@ini_set('max_execution_time', '3600');
622
-		@ini_set('max_input_time', '3600');
623
-
624
-		//try to set the maximum filesize to 10G
625
-		@ini_set('upload_max_filesize', '10G');
626
-		@ini_set('post_max_size', '10G');
627
-		@ini_set('file_uploads', '50');
628
-
629
-		self::setRequiredIniValues();
630
-		self::handleAuthHeaders();
631
-		self::registerAutoloaderCache();
632
-
633
-		// initialize intl fallback is necessary
634
-		\Patchwork\Utf8\Bootup::initIntl();
635
-		OC_Util::isSetLocaleWorking();
636
-
637
-		if (!defined('PHPUNIT_RUN')) {
638
-			OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
639
-			$debug = \OC::$server->getConfig()->getSystemValue('debug', false);
640
-			OC\Log\ErrorHandler::register($debug);
641
-		}
642
-
643
-		\OC::$server->getEventLogger()->start('init_session', 'Initialize session');
644
-		OC_App::loadApps(array('session'));
645
-		if (!self::$CLI) {
646
-			self::initSession();
647
-		}
648
-		\OC::$server->getEventLogger()->end('init_session');
649
-		self::checkConfig();
650
-		self::checkInstalled();
651
-
652
-		OC_Response::addSecurityHeaders();
653
-
654
-		self::performSameSiteCookieProtection();
655
-
656
-		if (!defined('OC_CONSOLE')) {
657
-			$errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
658
-			if (count($errors) > 0) {
659
-				if (self::$CLI) {
660
-					// Convert l10n string into regular string for usage in database
661
-					$staticErrors = [];
662
-					foreach ($errors as $error) {
663
-						echo $error['error'] . "\n";
664
-						echo $error['hint'] . "\n\n";
665
-						$staticErrors[] = [
666
-							'error' => (string)$error['error'],
667
-							'hint' => (string)$error['hint'],
668
-						];
669
-					}
670
-
671
-					try {
672
-						\OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
673
-					} catch (\Exception $e) {
674
-						echo('Writing to database failed');
675
-					}
676
-					exit(1);
677
-				} else {
678
-					OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
679
-					OC_Util::addStyle('guest');
680
-					OC_Template::printGuestPage('', 'error', array('errors' => $errors));
681
-					exit;
682
-				}
683
-			} elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
684
-				\OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
685
-			}
686
-		}
687
-		//try to set the session lifetime
688
-		$sessionLifeTime = self::getSessionLifeTime();
689
-		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
690
-
691
-		$systemConfig = \OC::$server->getSystemConfig();
692
-
693
-		// User and Groups
694
-		if (!$systemConfig->getValue("installed", false)) {
695
-			self::$server->getSession()->set('user_id', '');
696
-		}
697
-
698
-		OC_User::useBackend(new \OC\User\Database());
699
-		\OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
700
-
701
-		// Subscribe to the hook
702
-		\OCP\Util::connectHook(
703
-			'\OCA\Files_Sharing\API\Server2Server',
704
-			'preLoginNameUsedAsUserName',
705
-			'\OC\User\Database',
706
-			'preLoginNameUsedAsUserName'
707
-		);
708
-
709
-		//setup extra user backends
710
-		if (!\OCP\Util::needUpgrade()) {
711
-			OC_User::setupBackends();
712
-		} else {
713
-			// Run upgrades in incognito mode
714
-			OC_User::setIncognitoMode(true);
715
-		}
716
-
717
-		self::registerCleanupHooks();
718
-		self::registerFilesystemHooks();
719
-		self::registerShareHooks();
720
-		self::registerEncryptionWrapper();
721
-		self::registerEncryptionHooks();
722
-		self::registerAccountHooks();
723
-
724
-		// Make sure that the application class is not loaded before the database is setup
725
-		if ($systemConfig->getValue("installed", false)) {
726
-			$settings = new \OC\Settings\Application();
727
-			$settings->register();
728
-		}
729
-
730
-		//make sure temporary files are cleaned up
731
-		$tmpManager = \OC::$server->getTempManager();
732
-		register_shutdown_function(array($tmpManager, 'clean'));
733
-		$lockProvider = \OC::$server->getLockingProvider();
734
-		register_shutdown_function(array($lockProvider, 'releaseAll'));
735
-
736
-		// Check whether the sample configuration has been copied
737
-		if($systemConfig->getValue('copied_sample_config', false)) {
738
-			$l = \OC::$server->getL10N('lib');
739
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
740
-			header('Status: 503 Service Temporarily Unavailable');
741
-			OC_Template::printErrorPage(
742
-				$l->t('Sample configuration detected'),
743
-				$l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php')
744
-			);
745
-			return;
746
-		}
747
-
748
-		$request = \OC::$server->getRequest();
749
-		$host = $request->getInsecureServerHost();
750
-		/**
751
-		 * if the host passed in headers isn't trusted
752
-		 * FIXME: Should not be in here at all :see_no_evil:
753
-		 */
754
-		if (!OC::$CLI
755
-			// overwritehost is always trusted, workaround to not have to make
756
-			// \OC\AppFramework\Http\Request::getOverwriteHost public
757
-			&& self::$server->getConfig()->getSystemValue('overwritehost') === ''
758
-			&& !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
759
-			&& self::$server->getConfig()->getSystemValue('installed', false)
760
-		) {
761
-			// Allow access to CSS resources
762
-			$isScssRequest = false;
763
-			if(strpos($request->getPathInfo(), '/css/') === 0) {
764
-				$isScssRequest = true;
765
-			}
766
-
767
-			if(substr($request->getRequestUri(), -11) === '/status.php') {
768
-				OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
769
-				header('Status: 400 Bad Request');
770
-				header('Content-Type: application/json');
771
-				echo '{"error": "Trusted domain error.", "code": 15}';
772
-				exit();
773
-			}
774
-
775
-			if (!$isScssRequest) {
776
-				OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
777
-				header('Status: 400 Bad Request');
778
-
779
-				\OC::$server->getLogger()->warning(
780
-					'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
781
-					[
782
-						'app' => 'core',
783
-						'remoteAddress' => $request->getRemoteAddress(),
784
-						'host' => $host,
785
-					]
786
-				);
787
-
788
-				$tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
789
-				$tmpl->assign('domain', $host);
790
-				$tmpl->printPage();
791
-
792
-				exit();
793
-			}
794
-		}
795
-		\OC::$server->getEventLogger()->end('boot');
796
-	}
797
-
798
-	/**
799
-	 * register hooks for the cleanup of cache and bruteforce protection
800
-	 */
801
-	public static function registerCleanupHooks() {
802
-		//don't try to do this before we are properly setup
803
-		if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
804
-
805
-			// NOTE: This will be replaced to use OCP
806
-			$userSession = self::$server->getUserSession();
807
-			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
808
-				if (!defined('PHPUNIT_RUN')) {
809
-					// reset brute force delay for this IP address and username
810
-					$uid = \OC::$server->getUserSession()->getUser()->getUID();
811
-					$request = \OC::$server->getRequest();
812
-					$throttler = \OC::$server->getBruteForceThrottler();
813
-					$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
814
-				}
815
-
816
-				try {
817
-					$cache = new \OC\Cache\File();
818
-					$cache->gc();
819
-				} catch (\OC\ServerNotAvailableException $e) {
820
-					// not a GC exception, pass it on
821
-					throw $e;
822
-				} catch (\OC\ForbiddenException $e) {
823
-					// filesystem blocked for this request, ignore
824
-				} catch (\Exception $e) {
825
-					// a GC exception should not prevent users from using OC,
826
-					// so log the exception
827
-					\OC::$server->getLogger()->logException($e, [
828
-						'message' => 'Exception when running cache gc.',
829
-						'level' => \OCP\Util::WARN,
830
-						'app' => 'core',
831
-					]);
832
-				}
833
-			});
834
-		}
835
-	}
836
-
837
-	private static function registerEncryptionWrapper() {
838
-		$manager = self::$server->getEncryptionManager();
839
-		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
840
-	}
841
-
842
-	private static function registerEncryptionHooks() {
843
-		$enabled = self::$server->getEncryptionManager()->isEnabled();
844
-		if ($enabled) {
845
-			\OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
846
-			\OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
847
-			\OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
848
-			\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
849
-		}
850
-	}
851
-
852
-	private static function registerAccountHooks() {
853
-		$hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
854
-		\OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
855
-	}
856
-
857
-	/**
858
-	 * register hooks for the filesystem
859
-	 */
860
-	public static function registerFilesystemHooks() {
861
-		// Check for blacklisted files
862
-		OC_Hook::connect('OC_Filesystem', 'write', Filesystem::class, 'isBlacklisted');
863
-		OC_Hook::connect('OC_Filesystem', 'rename', Filesystem::class, 'isBlacklisted');
864
-	}
865
-
866
-	/**
867
-	 * register hooks for sharing
868
-	 */
869
-	public static function registerShareHooks() {
870
-		if (\OC::$server->getSystemConfig()->getValue('installed')) {
871
-			OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
872
-			OC_Hook::connect('OC_User', 'post_removeFromGroup', Hooks::class, 'post_removeFromGroup');
873
-			OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
874
-		}
875
-	}
876
-
877
-	protected static function registerAutoloaderCache() {
878
-		// The class loader takes an optional low-latency cache, which MUST be
879
-		// namespaced. The instanceid is used for namespacing, but might be
880
-		// unavailable at this point. Furthermore, it might not be possible to
881
-		// generate an instanceid via \OC_Util::getInstanceId() because the
882
-		// config file may not be writable. As such, we only register a class
883
-		// loader cache if instanceid is available without trying to create one.
884
-		$instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
885
-		if ($instanceId) {
886
-			try {
887
-				$memcacheFactory = \OC::$server->getMemCacheFactory();
888
-				self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
889
-			} catch (\Exception $ex) {
890
-			}
891
-		}
892
-	}
893
-
894
-	/**
895
-	 * Handle the request
896
-	 */
897
-	public static function handleRequest() {
898
-
899
-		\OC::$server->getEventLogger()->start('handle_request', 'Handle request');
900
-		$systemConfig = \OC::$server->getSystemConfig();
901
-		// load all the classpaths from the enabled apps so they are available
902
-		// in the routing files of each app
903
-		OC::loadAppClassPaths();
904
-
905
-		// Check if Nextcloud is installed or in maintenance (update) mode
906
-		if (!$systemConfig->getValue('installed', false)) {
907
-			\OC::$server->getSession()->clear();
908
-			$setupHelper = new OC\Setup(
909
-				$systemConfig,
910
-				\OC::$server->getIniWrapper(),
911
-				\OC::$server->getL10N('lib'),
912
-				\OC::$server->query(\OCP\Defaults::class),
913
-				\OC::$server->getLogger(),
914
-				\OC::$server->getSecureRandom(),
915
-				\OC::$server->query(\OC\Installer::class)
916
-			);
917
-			$controller = new OC\Core\Controller\SetupController($setupHelper);
918
-			$controller->run($_POST);
919
-			exit();
920
-		}
921
-
922
-		$request = \OC::$server->getRequest();
923
-		$requestPath = $request->getRawPathInfo();
924
-		if ($requestPath === '/heartbeat') {
925
-			return;
926
-		}
927
-		if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
928
-			self::checkMaintenanceMode();
929
-
930
-			if (\OCP\Util::needUpgrade()) {
931
-				if (function_exists('opcache_reset')) {
932
-					opcache_reset();
933
-				}
934
-				if (!$systemConfig->getValue('maintenance', false)) {
935
-					self::printUpgradePage($systemConfig);
936
-					exit();
937
-				}
938
-			}
939
-		}
940
-
941
-		// emergency app disabling
942
-		if ($requestPath === '/disableapp'
943
-			&& $request->getMethod() === 'POST'
944
-			&& ((array)$request->getParam('appid')) !== ''
945
-		) {
946
-			\OCP\JSON::callCheck();
947
-			\OCP\JSON::checkAdminUser();
948
-			$appIds = (array)$request->getParam('appid');
949
-			foreach($appIds as $appId) {
950
-				$appId = \OC_App::cleanAppId($appId);
951
-				\OC::$server->getAppManager()->disableApp($appId);
952
-			}
953
-			\OC_JSON::success();
954
-			exit();
955
-		}
956
-
957
-		// Always load authentication apps
958
-		OC_App::loadApps(['authentication']);
959
-
960
-		// Load minimum set of apps
961
-		if (!\OCP\Util::needUpgrade()
962
-			&& !$systemConfig->getValue('maintenance', false)) {
963
-			// For logged-in users: Load everything
964
-			if(\OC::$server->getUserSession()->isLoggedIn()) {
965
-				OC_App::loadApps();
966
-			} else {
967
-				// For guests: Load only filesystem and logging
968
-				OC_App::loadApps(array('filesystem', 'logging'));
969
-				self::handleLogin($request);
970
-			}
971
-		}
972
-
973
-		if (!self::$CLI) {
974
-			try {
975
-				if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
976
-					OC_App::loadApps(array('filesystem', 'logging'));
977
-					OC_App::loadApps();
978
-				}
979
-				OC_Util::setupFS();
980
-				OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
981
-				return;
982
-			} catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
983
-				//header('HTTP/1.0 404 Not Found');
984
-			} catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
985
-				OC_Response::setStatus(405);
986
-				return;
987
-			}
988
-		}
989
-
990
-		// Handle WebDAV
991
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
992
-			// not allowed any more to prevent people
993
-			// mounting this root directly.
994
-			// Users need to mount remote.php/webdav instead.
995
-			header('HTTP/1.1 405 Method Not Allowed');
996
-			header('Status: 405 Method Not Allowed');
997
-			return;
998
-		}
999
-
1000
-		// Someone is logged in
1001
-		if (\OC::$server->getUserSession()->isLoggedIn()) {
1002
-			OC_App::loadApps();
1003
-			OC_User::setupBackends();
1004
-			OC_Util::setupFS();
1005
-			// FIXME
1006
-			// Redirect to default application
1007
-			OC_Util::redirectToDefaultPage();
1008
-		} else {
1009
-			// Not handled and not logged in
1010
-			header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1011
-		}
1012
-	}
1013
-
1014
-	/**
1015
-	 * Check login: apache auth, auth token, basic auth
1016
-	 *
1017
-	 * @param OCP\IRequest $request
1018
-	 * @return boolean
1019
-	 */
1020
-	static function handleLogin(OCP\IRequest $request) {
1021
-		$userSession = self::$server->getUserSession();
1022
-		if (OC_User::handleApacheAuth()) {
1023
-			return true;
1024
-		}
1025
-		if ($userSession->tryTokenLogin($request)) {
1026
-			return true;
1027
-		}
1028
-		if (isset($_COOKIE['nc_username'])
1029
-			&& isset($_COOKIE['nc_token'])
1030
-			&& isset($_COOKIE['nc_session_id'])
1031
-			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1032
-			return true;
1033
-		}
1034
-		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1035
-			return true;
1036
-		}
1037
-		return false;
1038
-	}
1039
-
1040
-	protected static function handleAuthHeaders() {
1041
-		//copy http auth headers for apache+php-fcgid work around
1042
-		if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1043
-			$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1044
-		}
1045
-
1046
-		// Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1047
-		$vars = array(
1048
-			'HTTP_AUTHORIZATION', // apache+php-cgi work around
1049
-			'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1050
-		);
1051
-		foreach ($vars as $var) {
1052
-			if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1053
-				list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1054
-				$_SERVER['PHP_AUTH_USER'] = $name;
1055
-				$_SERVER['PHP_AUTH_PW'] = $password;
1056
-				break;
1057
-			}
1058
-		}
1059
-	}
70
+    /**
71
+     * Associative array for autoloading. classname => filename
72
+     */
73
+    public static $CLASSPATH = array();
74
+    /**
75
+     * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
76
+     */
77
+    public static $SERVERROOT = '';
78
+    /**
79
+     * the current request path relative to the Nextcloud root (e.g. files/index.php)
80
+     */
81
+    private static $SUBURI = '';
82
+    /**
83
+     * the Nextcloud root path for http requests (e.g. nextcloud/)
84
+     */
85
+    public static $WEBROOT = '';
86
+    /**
87
+     * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
88
+     * web path in 'url'
89
+     */
90
+    public static $APPSROOTS = array();
91
+
92
+    /**
93
+     * @var string
94
+     */
95
+    public static $configDir;
96
+
97
+    /**
98
+     * requested app
99
+     */
100
+    public static $REQUESTEDAPP = '';
101
+
102
+    /**
103
+     * check if Nextcloud runs in cli mode
104
+     */
105
+    public static $CLI = false;
106
+
107
+    /**
108
+     * @var \OC\Autoloader $loader
109
+     */
110
+    public static $loader = null;
111
+
112
+    /** @var \Composer\Autoload\ClassLoader $composerAutoloader */
113
+    public static $composerAutoloader = null;
114
+
115
+    /**
116
+     * @var \OC\Server
117
+     */
118
+    public static $server = null;
119
+
120
+    /**
121
+     * @var \OC\Config
122
+     */
123
+    private static $config = null;
124
+
125
+    /**
126
+     * @throws \RuntimeException when the 3rdparty directory is missing or
127
+     * the app path list is empty or contains an invalid path
128
+     */
129
+    public static function initPaths() {
130
+        if(defined('PHPUNIT_CONFIG_DIR')) {
131
+            self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
132
+        } elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
133
+            self::$configDir = OC::$SERVERROOT . '/tests/config/';
134
+        } elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
+            self::$configDir = rtrim($dir, '/') . '/';
136
+        } else {
137
+            self::$configDir = OC::$SERVERROOT . '/config/';
138
+        }
139
+        self::$config = new \OC\Config(self::$configDir);
140
+
141
+        OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
142
+        /**
143
+         * FIXME: The following lines are required because we can't yet instantiate
144
+         *        \OC::$server->getRequest() since \OC::$server does not yet exist.
145
+         */
146
+        $params = [
147
+            'server' => [
148
+                'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
149
+                'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
150
+            ],
151
+        ];
152
+        $fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
153
+        $scriptName = $fakeRequest->getScriptName();
154
+        if (substr($scriptName, -1) == '/') {
155
+            $scriptName .= 'index.php';
156
+            //make sure suburi follows the same rules as scriptName
157
+            if (substr(OC::$SUBURI, -9) != 'index.php') {
158
+                if (substr(OC::$SUBURI, -1) != '/') {
159
+                    OC::$SUBURI = OC::$SUBURI . '/';
160
+                }
161
+                OC::$SUBURI = OC::$SUBURI . 'index.php';
162
+            }
163
+        }
164
+
165
+
166
+        if (OC::$CLI) {
167
+            OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
168
+        } else {
169
+            if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
170
+                OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
171
+
172
+                if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
173
+                    OC::$WEBROOT = '/' . OC::$WEBROOT;
174
+                }
175
+            } else {
176
+                // The scriptName is not ending with OC::$SUBURI
177
+                // This most likely means that we are calling from CLI.
178
+                // However some cron jobs still need to generate
179
+                // a web URL, so we use overwritewebroot as a fallback.
180
+                OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
181
+            }
182
+
183
+            // Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
184
+            // slash which is required by URL generation.
185
+            if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
186
+                    substr($_SERVER['REQUEST_URI'], -1) !== '/') {
187
+                header('Location: '.\OC::$WEBROOT.'/');
188
+                exit();
189
+            }
190
+        }
191
+
192
+        // search the apps folder
193
+        $config_paths = self::$config->getValue('apps_paths', array());
194
+        if (!empty($config_paths)) {
195
+            foreach ($config_paths as $paths) {
196
+                if (isset($paths['url']) && isset($paths['path'])) {
197
+                    $paths['url'] = rtrim($paths['url'], '/');
198
+                    $paths['path'] = rtrim($paths['path'], '/');
199
+                    OC::$APPSROOTS[] = $paths;
200
+                }
201
+            }
202
+        } elseif (file_exists(OC::$SERVERROOT . '/apps')) {
203
+            OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
204
+        } elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
205
+            OC::$APPSROOTS[] = array(
206
+                'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
207
+                'url' => '/apps',
208
+                'writable' => true
209
+            );
210
+        }
211
+
212
+        if (empty(OC::$APPSROOTS)) {
213
+            throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
214
+                . ' or the folder above. You can also configure the location in the config.php file.');
215
+        }
216
+        $paths = array();
217
+        foreach (OC::$APPSROOTS as $path) {
218
+            $paths[] = $path['path'];
219
+            if (!is_dir($path['path'])) {
220
+                throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
221
+                    . ' Nextcloud folder or the folder above. You can also configure the location in the'
222
+                    . ' config.php file.', $path['path']));
223
+            }
224
+        }
225
+
226
+        // set the right include path
227
+        set_include_path(
228
+            implode(PATH_SEPARATOR, $paths)
229
+        );
230
+    }
231
+
232
+    public static function checkConfig() {
233
+        $l = \OC::$server->getL10N('lib');
234
+
235
+        // Create config if it does not already exist
236
+        $configFilePath = self::$configDir .'/config.php';
237
+        if(!file_exists($configFilePath)) {
238
+            @touch($configFilePath);
239
+        }
240
+
241
+        // Check if config is writable
242
+        $configFileWritable = is_writable($configFilePath);
243
+        if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
244
+            || !$configFileWritable && \OCP\Util::needUpgrade()) {
245
+
246
+            $urlGenerator = \OC::$server->getURLGenerator();
247
+
248
+            if (self::$CLI) {
249
+                echo $l->t('Cannot write into "config" directory!')."\n";
250
+                echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
251
+                echo "\n";
252
+                echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
253
+                exit;
254
+            } else {
255
+                OC_Template::printErrorPage(
256
+                    $l->t('Cannot write into "config" directory!'),
257
+                    $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
258
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
259
+                );
260
+            }
261
+        }
262
+    }
263
+
264
+    public static function checkInstalled() {
265
+        if (defined('OC_CONSOLE')) {
266
+            return;
267
+        }
268
+        // Redirect to installer if not installed
269
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
270
+            if (OC::$CLI) {
271
+                throw new Exception('Not installed');
272
+            } else {
273
+                $url = OC::$WEBROOT . '/index.php';
274
+                header('Location: ' . $url);
275
+            }
276
+            exit();
277
+        }
278
+    }
279
+
280
+    public static function checkMaintenanceMode() {
281
+        // Allow ajax update script to execute without being stopped
282
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
283
+            // send http status 503
284
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
285
+            header('Status: 503 Service Temporarily Unavailable');
286
+            header('Retry-After: 120');
287
+
288
+            // render error page
289
+            $template = new OC_Template('', 'update.user', 'guest');
290
+            OC_Util::addScript('maintenance-check');
291
+            OC_Util::addStyle('core', 'guest');
292
+            $template->printPage();
293
+            die();
294
+        }
295
+    }
296
+
297
+    /**
298
+     * Prints the upgrade page
299
+     *
300
+     * @param \OC\SystemConfig $systemConfig
301
+     */
302
+    private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
303
+        $disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
304
+        $tooBig = false;
305
+        if (!$disableWebUpdater) {
306
+            $apps = \OC::$server->getAppManager();
307
+            if ($apps->isInstalled('user_ldap')) {
308
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
309
+
310
+                $result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
311
+                    ->from('ldap_user_mapping')
312
+                    ->execute();
313
+                $row = $result->fetch();
314
+                $result->closeCursor();
315
+
316
+                $tooBig = ($row['user_count'] > 50);
317
+            }
318
+            if (!$tooBig && $apps->isInstalled('user_saml')) {
319
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
320
+
321
+                $result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
322
+                    ->from('user_saml_users')
323
+                    ->execute();
324
+                $row = $result->fetch();
325
+                $result->closeCursor();
326
+
327
+                $tooBig = ($row['user_count'] > 50);
328
+            }
329
+            if (!$tooBig) {
330
+                // count users
331
+                $stats = \OC::$server->getUserManager()->countUsers();
332
+                $totalUsers = array_sum($stats);
333
+                $tooBig = ($totalUsers > 50);
334
+            }
335
+        }
336
+        $ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
337
+            $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
338
+
339
+        if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
340
+            // send http status 503
341
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
342
+            header('Status: 503 Service Temporarily Unavailable');
343
+            header('Retry-After: 120');
344
+
345
+            // render error page
346
+            $template = new OC_Template('', 'update.use-cli', 'guest');
347
+            $template->assign('productName', 'nextcloud'); // for now
348
+            $template->assign('version', OC_Util::getVersionString());
349
+            $template->assign('tooBig', $tooBig);
350
+
351
+            $template->printPage();
352
+            die();
353
+        }
354
+
355
+        // check whether this is a core update or apps update
356
+        $installedVersion = $systemConfig->getValue('version', '0.0.0');
357
+        $currentVersion = implode('.', \OCP\Util::getVersion());
358
+
359
+        // if not a core upgrade, then it's apps upgrade
360
+        $isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
361
+
362
+        $oldTheme = $systemConfig->getValue('theme');
363
+        $systemConfig->setValue('theme', '');
364
+        OC_Util::addScript('config'); // needed for web root
365
+        OC_Util::addScript('update');
366
+
367
+        /** @var \OC\App\AppManager $appManager */
368
+        $appManager = \OC::$server->getAppManager();
369
+
370
+        $tmpl = new OC_Template('', 'update.admin', 'guest');
371
+        $tmpl->assign('version', OC_Util::getVersionString());
372
+        $tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
373
+
374
+        // get third party apps
375
+        $ocVersion = \OCP\Util::getVersion();
376
+        $incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
377
+        $incompatibleShippedApps = [];
378
+        foreach ($incompatibleApps as $appInfo) {
379
+            if ($appManager->isShipped($appInfo['id'])) {
380
+                $incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
381
+            }
382
+        }
383
+
384
+        if (!empty($incompatibleShippedApps)) {
385
+            $l = \OC::$server->getL10N('core');
386
+            $hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
387
+            throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
388
+        }
389
+
390
+        $tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
391
+        $tmpl->assign('incompatibleAppsList', $incompatibleApps);
392
+        $tmpl->assign('productName', 'Nextcloud'); // for now
393
+        $tmpl->assign('oldTheme', $oldTheme);
394
+        $tmpl->printPage();
395
+    }
396
+
397
+    public static function initSession() {
398
+        if(self::$server->getRequest()->getServerProtocol() === 'https') {
399
+            ini_set('session.cookie_secure', true);
400
+        }
401
+
402
+        // prevents javascript from accessing php session cookies
403
+        ini_set('session.cookie_httponly', 'true');
404
+
405
+        // set the cookie path to the Nextcloud directory
406
+        $cookie_path = OC::$WEBROOT ? : '/';
407
+        ini_set('session.cookie_path', $cookie_path);
408
+
409
+        // Let the session name be changed in the initSession Hook
410
+        $sessionName = OC_Util::getInstanceId();
411
+
412
+        try {
413
+            // Allow session apps to create a custom session object
414
+            $useCustomSession = false;
415
+            $session = self::$server->getSession();
416
+            OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
417
+            if (!$useCustomSession) {
418
+                // set the session name to the instance id - which is unique
419
+                $session = new \OC\Session\Internal($sessionName);
420
+            }
421
+
422
+            $cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
423
+            $session = $cryptoWrapper->wrapSession($session);
424
+            self::$server->setSession($session);
425
+
426
+            // if session can't be started break with http 500 error
427
+        } catch (Exception $e) {
428
+            \OCP\Util::logException('base', $e);
429
+            //show the user a detailed error page
430
+            OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
431
+            OC_Template::printExceptionErrorPage($e);
432
+            die();
433
+        }
434
+
435
+        $sessionLifeTime = self::getSessionLifeTime();
436
+
437
+        // session timeout
438
+        if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
439
+            if (isset($_COOKIE[session_name()])) {
440
+                setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
441
+            }
442
+            \OC::$server->getUserSession()->logout();
443
+        }
444
+
445
+        $session->set('LAST_ACTIVITY', time());
446
+    }
447
+
448
+    /**
449
+     * @return string
450
+     */
451
+    private static function getSessionLifeTime() {
452
+        return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
453
+    }
454
+
455
+    public static function loadAppClassPaths() {
456
+        foreach (OC_App::getEnabledApps() as $app) {
457
+            $appPath = OC_App::getAppPath($app);
458
+            if ($appPath === false) {
459
+                continue;
460
+            }
461
+
462
+            $file = $appPath . '/appinfo/classpath.php';
463
+            if (file_exists($file)) {
464
+                require_once $file;
465
+            }
466
+        }
467
+    }
468
+
469
+    /**
470
+     * Try to set some values to the required Nextcloud default
471
+     */
472
+    public static function setRequiredIniValues() {
473
+        @ini_set('default_charset', 'UTF-8');
474
+        @ini_set('gd.jpeg_ignore_warning', '1');
475
+    }
476
+
477
+    /**
478
+     * Send the same site cookies
479
+     */
480
+    private static function sendSameSiteCookies() {
481
+        $cookieParams = session_get_cookie_params();
482
+        $secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
483
+        $policies = [
484
+            'lax',
485
+            'strict',
486
+        ];
487
+
488
+        // Append __Host to the cookie if it meets the requirements
489
+        $cookiePrefix = '';
490
+        if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
491
+            $cookiePrefix = '__Host-';
492
+        }
493
+
494
+        foreach($policies as $policy) {
495
+            header(
496
+                sprintf(
497
+                    'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
498
+                    $cookiePrefix,
499
+                    $policy,
500
+                    $cookieParams['path'],
501
+                    $policy
502
+                ),
503
+                false
504
+            );
505
+        }
506
+    }
507
+
508
+    /**
509
+     * Same Site cookie to further mitigate CSRF attacks. This cookie has to
510
+     * be set in every request if cookies are sent to add a second level of
511
+     * defense against CSRF.
512
+     *
513
+     * If the cookie is not sent this will set the cookie and reload the page.
514
+     * We use an additional cookie since we want to protect logout CSRF and
515
+     * also we can't directly interfere with PHP's session mechanism.
516
+     */
517
+    private static function performSameSiteCookieProtection() {
518
+        $request = \OC::$server->getRequest();
519
+
520
+        // Some user agents are notorious and don't really properly follow HTTP
521
+        // specifications. For those, have an automated opt-out. Since the protection
522
+        // for remote.php is applied in base.php as starting point we need to opt out
523
+        // here.
524
+        $incompatibleUserAgents = [
525
+            // OS X Finder
526
+            '/^WebDAVFS/',
527
+        ];
528
+        if($request->isUserAgent($incompatibleUserAgents)) {
529
+            return;
530
+        }
531
+
532
+        if(count($_COOKIE) > 0) {
533
+            $requestUri = $request->getScriptName();
534
+            $processingScript = explode('/', $requestUri);
535
+            $processingScript = $processingScript[count($processingScript)-1];
536
+
537
+            // index.php routes are handled in the middleware
538
+            if($processingScript === 'index.php') {
539
+                return;
540
+            }
541
+
542
+            // All other endpoints require the lax and the strict cookie
543
+            if(!$request->passesStrictCookieCheck()) {
544
+                self::sendSameSiteCookies();
545
+                // Debug mode gets access to the resources without strict cookie
546
+                // due to the fact that the SabreDAV browser also lives there.
547
+                if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
548
+                    http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
549
+                    exit();
550
+                }
551
+            }
552
+        } elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
553
+            self::sendSameSiteCookies();
554
+        }
555
+    }
556
+
557
+    public static function init() {
558
+        // calculate the root directories
559
+        OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
560
+
561
+        // register autoloader
562
+        $loaderStart = microtime(true);
563
+        require_once __DIR__ . '/autoloader.php';
564
+        self::$loader = new \OC\Autoloader([
565
+            OC::$SERVERROOT . '/lib/private/legacy',
566
+        ]);
567
+        if (defined('PHPUNIT_RUN')) {
568
+            self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
569
+        }
570
+        spl_autoload_register(array(self::$loader, 'load'));
571
+        $loaderEnd = microtime(true);
572
+
573
+        self::$CLI = (php_sapi_name() == 'cli');
574
+
575
+        // Add default composer PSR-4 autoloader
576
+        self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
577
+
578
+        try {
579
+            self::initPaths();
580
+            // setup 3rdparty autoloader
581
+            $vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
582
+            if (!file_exists($vendorAutoLoad)) {
583
+                throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
584
+            }
585
+            require_once $vendorAutoLoad;
586
+
587
+        } catch (\RuntimeException $e) {
588
+            if (!self::$CLI) {
589
+                $claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
590
+                $protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
591
+                header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
592
+            }
593
+            // we can't use the template error page here, because this needs the
594
+            // DI container which isn't available yet
595
+            print($e->getMessage());
596
+            exit();
597
+        }
598
+
599
+        // setup the basic server
600
+        self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
601
+        \OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
602
+        \OC::$server->getEventLogger()->start('boot', 'Initialize');
603
+
604
+        // Don't display errors and log them
605
+        error_reporting(E_ALL | E_STRICT);
606
+        @ini_set('display_errors', '0');
607
+        @ini_set('log_errors', '1');
608
+
609
+        if(!date_default_timezone_set('UTC')) {
610
+            throw new \RuntimeException('Could not set timezone to UTC');
611
+        }
612
+
613
+        //try to configure php to enable big file uploads.
614
+        //this doesn´t work always depending on the webserver and php configuration.
615
+        //Let´s try to overwrite some defaults anyway
616
+
617
+        //try to set the maximum execution time to 60min
618
+        if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
619
+            @set_time_limit(3600);
620
+        }
621
+        @ini_set('max_execution_time', '3600');
622
+        @ini_set('max_input_time', '3600');
623
+
624
+        //try to set the maximum filesize to 10G
625
+        @ini_set('upload_max_filesize', '10G');
626
+        @ini_set('post_max_size', '10G');
627
+        @ini_set('file_uploads', '50');
628
+
629
+        self::setRequiredIniValues();
630
+        self::handleAuthHeaders();
631
+        self::registerAutoloaderCache();
632
+
633
+        // initialize intl fallback is necessary
634
+        \Patchwork\Utf8\Bootup::initIntl();
635
+        OC_Util::isSetLocaleWorking();
636
+
637
+        if (!defined('PHPUNIT_RUN')) {
638
+            OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
639
+            $debug = \OC::$server->getConfig()->getSystemValue('debug', false);
640
+            OC\Log\ErrorHandler::register($debug);
641
+        }
642
+
643
+        \OC::$server->getEventLogger()->start('init_session', 'Initialize session');
644
+        OC_App::loadApps(array('session'));
645
+        if (!self::$CLI) {
646
+            self::initSession();
647
+        }
648
+        \OC::$server->getEventLogger()->end('init_session');
649
+        self::checkConfig();
650
+        self::checkInstalled();
651
+
652
+        OC_Response::addSecurityHeaders();
653
+
654
+        self::performSameSiteCookieProtection();
655
+
656
+        if (!defined('OC_CONSOLE')) {
657
+            $errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
658
+            if (count($errors) > 0) {
659
+                if (self::$CLI) {
660
+                    // Convert l10n string into regular string for usage in database
661
+                    $staticErrors = [];
662
+                    foreach ($errors as $error) {
663
+                        echo $error['error'] . "\n";
664
+                        echo $error['hint'] . "\n\n";
665
+                        $staticErrors[] = [
666
+                            'error' => (string)$error['error'],
667
+                            'hint' => (string)$error['hint'],
668
+                        ];
669
+                    }
670
+
671
+                    try {
672
+                        \OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
673
+                    } catch (\Exception $e) {
674
+                        echo('Writing to database failed');
675
+                    }
676
+                    exit(1);
677
+                } else {
678
+                    OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
679
+                    OC_Util::addStyle('guest');
680
+                    OC_Template::printGuestPage('', 'error', array('errors' => $errors));
681
+                    exit;
682
+                }
683
+            } elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
684
+                \OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
685
+            }
686
+        }
687
+        //try to set the session lifetime
688
+        $sessionLifeTime = self::getSessionLifeTime();
689
+        @ini_set('gc_maxlifetime', (string)$sessionLifeTime);
690
+
691
+        $systemConfig = \OC::$server->getSystemConfig();
692
+
693
+        // User and Groups
694
+        if (!$systemConfig->getValue("installed", false)) {
695
+            self::$server->getSession()->set('user_id', '');
696
+        }
697
+
698
+        OC_User::useBackend(new \OC\User\Database());
699
+        \OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
700
+
701
+        // Subscribe to the hook
702
+        \OCP\Util::connectHook(
703
+            '\OCA\Files_Sharing\API\Server2Server',
704
+            'preLoginNameUsedAsUserName',
705
+            '\OC\User\Database',
706
+            'preLoginNameUsedAsUserName'
707
+        );
708
+
709
+        //setup extra user backends
710
+        if (!\OCP\Util::needUpgrade()) {
711
+            OC_User::setupBackends();
712
+        } else {
713
+            // Run upgrades in incognito mode
714
+            OC_User::setIncognitoMode(true);
715
+        }
716
+
717
+        self::registerCleanupHooks();
718
+        self::registerFilesystemHooks();
719
+        self::registerShareHooks();
720
+        self::registerEncryptionWrapper();
721
+        self::registerEncryptionHooks();
722
+        self::registerAccountHooks();
723
+
724
+        // Make sure that the application class is not loaded before the database is setup
725
+        if ($systemConfig->getValue("installed", false)) {
726
+            $settings = new \OC\Settings\Application();
727
+            $settings->register();
728
+        }
729
+
730
+        //make sure temporary files are cleaned up
731
+        $tmpManager = \OC::$server->getTempManager();
732
+        register_shutdown_function(array($tmpManager, 'clean'));
733
+        $lockProvider = \OC::$server->getLockingProvider();
734
+        register_shutdown_function(array($lockProvider, 'releaseAll'));
735
+
736
+        // Check whether the sample configuration has been copied
737
+        if($systemConfig->getValue('copied_sample_config', false)) {
738
+            $l = \OC::$server->getL10N('lib');
739
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
740
+            header('Status: 503 Service Temporarily Unavailable');
741
+            OC_Template::printErrorPage(
742
+                $l->t('Sample configuration detected'),
743
+                $l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php')
744
+            );
745
+            return;
746
+        }
747
+
748
+        $request = \OC::$server->getRequest();
749
+        $host = $request->getInsecureServerHost();
750
+        /**
751
+         * if the host passed in headers isn't trusted
752
+         * FIXME: Should not be in here at all :see_no_evil:
753
+         */
754
+        if (!OC::$CLI
755
+            // overwritehost is always trusted, workaround to not have to make
756
+            // \OC\AppFramework\Http\Request::getOverwriteHost public
757
+            && self::$server->getConfig()->getSystemValue('overwritehost') === ''
758
+            && !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
759
+            && self::$server->getConfig()->getSystemValue('installed', false)
760
+        ) {
761
+            // Allow access to CSS resources
762
+            $isScssRequest = false;
763
+            if(strpos($request->getPathInfo(), '/css/') === 0) {
764
+                $isScssRequest = true;
765
+            }
766
+
767
+            if(substr($request->getRequestUri(), -11) === '/status.php') {
768
+                OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
769
+                header('Status: 400 Bad Request');
770
+                header('Content-Type: application/json');
771
+                echo '{"error": "Trusted domain error.", "code": 15}';
772
+                exit();
773
+            }
774
+
775
+            if (!$isScssRequest) {
776
+                OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
777
+                header('Status: 400 Bad Request');
778
+
779
+                \OC::$server->getLogger()->warning(
780
+                    'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
781
+                    [
782
+                        'app' => 'core',
783
+                        'remoteAddress' => $request->getRemoteAddress(),
784
+                        'host' => $host,
785
+                    ]
786
+                );
787
+
788
+                $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
789
+                $tmpl->assign('domain', $host);
790
+                $tmpl->printPage();
791
+
792
+                exit();
793
+            }
794
+        }
795
+        \OC::$server->getEventLogger()->end('boot');
796
+    }
797
+
798
+    /**
799
+     * register hooks for the cleanup of cache and bruteforce protection
800
+     */
801
+    public static function registerCleanupHooks() {
802
+        //don't try to do this before we are properly setup
803
+        if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
804
+
805
+            // NOTE: This will be replaced to use OCP
806
+            $userSession = self::$server->getUserSession();
807
+            $userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
808
+                if (!defined('PHPUNIT_RUN')) {
809
+                    // reset brute force delay for this IP address and username
810
+                    $uid = \OC::$server->getUserSession()->getUser()->getUID();
811
+                    $request = \OC::$server->getRequest();
812
+                    $throttler = \OC::$server->getBruteForceThrottler();
813
+                    $throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
814
+                }
815
+
816
+                try {
817
+                    $cache = new \OC\Cache\File();
818
+                    $cache->gc();
819
+                } catch (\OC\ServerNotAvailableException $e) {
820
+                    // not a GC exception, pass it on
821
+                    throw $e;
822
+                } catch (\OC\ForbiddenException $e) {
823
+                    // filesystem blocked for this request, ignore
824
+                } catch (\Exception $e) {
825
+                    // a GC exception should not prevent users from using OC,
826
+                    // so log the exception
827
+                    \OC::$server->getLogger()->logException($e, [
828
+                        'message' => 'Exception when running cache gc.',
829
+                        'level' => \OCP\Util::WARN,
830
+                        'app' => 'core',
831
+                    ]);
832
+                }
833
+            });
834
+        }
835
+    }
836
+
837
+    private static function registerEncryptionWrapper() {
838
+        $manager = self::$server->getEncryptionManager();
839
+        \OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
840
+    }
841
+
842
+    private static function registerEncryptionHooks() {
843
+        $enabled = self::$server->getEncryptionManager()->isEnabled();
844
+        if ($enabled) {
845
+            \OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
846
+            \OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
847
+            \OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
848
+            \OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
849
+        }
850
+    }
851
+
852
+    private static function registerAccountHooks() {
853
+        $hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
854
+        \OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
855
+    }
856
+
857
+    /**
858
+     * register hooks for the filesystem
859
+     */
860
+    public static function registerFilesystemHooks() {
861
+        // Check for blacklisted files
862
+        OC_Hook::connect('OC_Filesystem', 'write', Filesystem::class, 'isBlacklisted');
863
+        OC_Hook::connect('OC_Filesystem', 'rename', Filesystem::class, 'isBlacklisted');
864
+    }
865
+
866
+    /**
867
+     * register hooks for sharing
868
+     */
869
+    public static function registerShareHooks() {
870
+        if (\OC::$server->getSystemConfig()->getValue('installed')) {
871
+            OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
872
+            OC_Hook::connect('OC_User', 'post_removeFromGroup', Hooks::class, 'post_removeFromGroup');
873
+            OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
874
+        }
875
+    }
876
+
877
+    protected static function registerAutoloaderCache() {
878
+        // The class loader takes an optional low-latency cache, which MUST be
879
+        // namespaced. The instanceid is used for namespacing, but might be
880
+        // unavailable at this point. Furthermore, it might not be possible to
881
+        // generate an instanceid via \OC_Util::getInstanceId() because the
882
+        // config file may not be writable. As such, we only register a class
883
+        // loader cache if instanceid is available without trying to create one.
884
+        $instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
885
+        if ($instanceId) {
886
+            try {
887
+                $memcacheFactory = \OC::$server->getMemCacheFactory();
888
+                self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
889
+            } catch (\Exception $ex) {
890
+            }
891
+        }
892
+    }
893
+
894
+    /**
895
+     * Handle the request
896
+     */
897
+    public static function handleRequest() {
898
+
899
+        \OC::$server->getEventLogger()->start('handle_request', 'Handle request');
900
+        $systemConfig = \OC::$server->getSystemConfig();
901
+        // load all the classpaths from the enabled apps so they are available
902
+        // in the routing files of each app
903
+        OC::loadAppClassPaths();
904
+
905
+        // Check if Nextcloud is installed or in maintenance (update) mode
906
+        if (!$systemConfig->getValue('installed', false)) {
907
+            \OC::$server->getSession()->clear();
908
+            $setupHelper = new OC\Setup(
909
+                $systemConfig,
910
+                \OC::$server->getIniWrapper(),
911
+                \OC::$server->getL10N('lib'),
912
+                \OC::$server->query(\OCP\Defaults::class),
913
+                \OC::$server->getLogger(),
914
+                \OC::$server->getSecureRandom(),
915
+                \OC::$server->query(\OC\Installer::class)
916
+            );
917
+            $controller = new OC\Core\Controller\SetupController($setupHelper);
918
+            $controller->run($_POST);
919
+            exit();
920
+        }
921
+
922
+        $request = \OC::$server->getRequest();
923
+        $requestPath = $request->getRawPathInfo();
924
+        if ($requestPath === '/heartbeat') {
925
+            return;
926
+        }
927
+        if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
928
+            self::checkMaintenanceMode();
929
+
930
+            if (\OCP\Util::needUpgrade()) {
931
+                if (function_exists('opcache_reset')) {
932
+                    opcache_reset();
933
+                }
934
+                if (!$systemConfig->getValue('maintenance', false)) {
935
+                    self::printUpgradePage($systemConfig);
936
+                    exit();
937
+                }
938
+            }
939
+        }
940
+
941
+        // emergency app disabling
942
+        if ($requestPath === '/disableapp'
943
+            && $request->getMethod() === 'POST'
944
+            && ((array)$request->getParam('appid')) !== ''
945
+        ) {
946
+            \OCP\JSON::callCheck();
947
+            \OCP\JSON::checkAdminUser();
948
+            $appIds = (array)$request->getParam('appid');
949
+            foreach($appIds as $appId) {
950
+                $appId = \OC_App::cleanAppId($appId);
951
+                \OC::$server->getAppManager()->disableApp($appId);
952
+            }
953
+            \OC_JSON::success();
954
+            exit();
955
+        }
956
+
957
+        // Always load authentication apps
958
+        OC_App::loadApps(['authentication']);
959
+
960
+        // Load minimum set of apps
961
+        if (!\OCP\Util::needUpgrade()
962
+            && !$systemConfig->getValue('maintenance', false)) {
963
+            // For logged-in users: Load everything
964
+            if(\OC::$server->getUserSession()->isLoggedIn()) {
965
+                OC_App::loadApps();
966
+            } else {
967
+                // For guests: Load only filesystem and logging
968
+                OC_App::loadApps(array('filesystem', 'logging'));
969
+                self::handleLogin($request);
970
+            }
971
+        }
972
+
973
+        if (!self::$CLI) {
974
+            try {
975
+                if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
976
+                    OC_App::loadApps(array('filesystem', 'logging'));
977
+                    OC_App::loadApps();
978
+                }
979
+                OC_Util::setupFS();
980
+                OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
981
+                return;
982
+            } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
983
+                //header('HTTP/1.0 404 Not Found');
984
+            } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
985
+                OC_Response::setStatus(405);
986
+                return;
987
+            }
988
+        }
989
+
990
+        // Handle WebDAV
991
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
992
+            // not allowed any more to prevent people
993
+            // mounting this root directly.
994
+            // Users need to mount remote.php/webdav instead.
995
+            header('HTTP/1.1 405 Method Not Allowed');
996
+            header('Status: 405 Method Not Allowed');
997
+            return;
998
+        }
999
+
1000
+        // Someone is logged in
1001
+        if (\OC::$server->getUserSession()->isLoggedIn()) {
1002
+            OC_App::loadApps();
1003
+            OC_User::setupBackends();
1004
+            OC_Util::setupFS();
1005
+            // FIXME
1006
+            // Redirect to default application
1007
+            OC_Util::redirectToDefaultPage();
1008
+        } else {
1009
+            // Not handled and not logged in
1010
+            header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1011
+        }
1012
+    }
1013
+
1014
+    /**
1015
+     * Check login: apache auth, auth token, basic auth
1016
+     *
1017
+     * @param OCP\IRequest $request
1018
+     * @return boolean
1019
+     */
1020
+    static function handleLogin(OCP\IRequest $request) {
1021
+        $userSession = self::$server->getUserSession();
1022
+        if (OC_User::handleApacheAuth()) {
1023
+            return true;
1024
+        }
1025
+        if ($userSession->tryTokenLogin($request)) {
1026
+            return true;
1027
+        }
1028
+        if (isset($_COOKIE['nc_username'])
1029
+            && isset($_COOKIE['nc_token'])
1030
+            && isset($_COOKIE['nc_session_id'])
1031
+            && $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1032
+            return true;
1033
+        }
1034
+        if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1035
+            return true;
1036
+        }
1037
+        return false;
1038
+    }
1039
+
1040
+    protected static function handleAuthHeaders() {
1041
+        //copy http auth headers for apache+php-fcgid work around
1042
+        if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1043
+            $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1044
+        }
1045
+
1046
+        // Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1047
+        $vars = array(
1048
+            'HTTP_AUTHORIZATION', // apache+php-cgi work around
1049
+            'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1050
+        );
1051
+        foreach ($vars as $var) {
1052
+            if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1053
+                list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1054
+                $_SERVER['PHP_AUTH_USER'] = $name;
1055
+                $_SERVER['PHP_AUTH_PW'] = $password;
1056
+                break;
1057
+            }
1058
+        }
1059
+    }
1060 1060
 }
1061 1061
 
1062 1062
 OC::init();
Please login to merge, or discard this patch.
Spacing   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -127,14 +127,14 @@  discard block
 block discarded – undo
127 127
 	 * the app path list is empty or contains an invalid path
128 128
 	 */
129 129
 	public static function initPaths() {
130
-		if(defined('PHPUNIT_CONFIG_DIR')) {
131
-			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
132
-		} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
133
-			self::$configDir = OC::$SERVERROOT . '/tests/config/';
134
-		} elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
-			self::$configDir = rtrim($dir, '/') . '/';
130
+		if (defined('PHPUNIT_CONFIG_DIR')) {
131
+			self::$configDir = OC::$SERVERROOT.'/'.PHPUNIT_CONFIG_DIR.'/';
132
+		} elseif (defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT.'/tests/config/')) {
133
+			self::$configDir = OC::$SERVERROOT.'/tests/config/';
134
+		} elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
+			self::$configDir = rtrim($dir, '/').'/';
136 136
 		} else {
137
-			self::$configDir = OC::$SERVERROOT . '/config/';
137
+			self::$configDir = OC::$SERVERROOT.'/config/';
138 138
 		}
139 139
 		self::$config = new \OC\Config(self::$configDir);
140 140
 
@@ -156,9 +156,9 @@  discard block
 block discarded – undo
156 156
 			//make sure suburi follows the same rules as scriptName
157 157
 			if (substr(OC::$SUBURI, -9) != 'index.php') {
158 158
 				if (substr(OC::$SUBURI, -1) != '/') {
159
-					OC::$SUBURI = OC::$SUBURI . '/';
159
+					OC::$SUBURI = OC::$SUBURI.'/';
160 160
 				}
161
-				OC::$SUBURI = OC::$SUBURI . 'index.php';
161
+				OC::$SUBURI = OC::$SUBURI.'index.php';
162 162
 			}
163 163
 		}
164 164
 
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
 				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
171 171
 
172 172
 				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
173
-					OC::$WEBROOT = '/' . OC::$WEBROOT;
173
+					OC::$WEBROOT = '/'.OC::$WEBROOT;
174 174
 				}
175 175
 			} else {
176 176
 				// The scriptName is not ending with OC::$SUBURI
@@ -199,11 +199,11 @@  discard block
 block discarded – undo
199 199
 					OC::$APPSROOTS[] = $paths;
200 200
 				}
201 201
 			}
202
-		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
203
-			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
204
-		} elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
202
+		} elseif (file_exists(OC::$SERVERROOT.'/apps')) {
203
+			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT.'/apps', 'url' => '/apps', 'writable' => true);
204
+		} elseif (file_exists(OC::$SERVERROOT.'/../apps')) {
205 205
 			OC::$APPSROOTS[] = array(
206
-				'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
206
+				'path' => rtrim(dirname(OC::$SERVERROOT), '/').'/apps',
207 207
 				'url' => '/apps',
208 208
 				'writable' => true
209 209
 			);
@@ -233,8 +233,8 @@  discard block
 block discarded – undo
233 233
 		$l = \OC::$server->getL10N('lib');
234 234
 
235 235
 		// Create config if it does not already exist
236
-		$configFilePath = self::$configDir .'/config.php';
237
-		if(!file_exists($configFilePath)) {
236
+		$configFilePath = self::$configDir.'/config.php';
237
+		if (!file_exists($configFilePath)) {
238 238
 			@touch($configFilePath);
239 239
 		}
240 240
 
@@ -249,13 +249,13 @@  discard block
 block discarded – undo
249 249
 				echo $l->t('Cannot write into "config" directory!')."\n";
250 250
 				echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
251 251
 				echo "\n";
252
-				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
252
+				echo $l->t('See %s', [$urlGenerator->linkToDocs('admin-dir_permissions')])."\n";
253 253
 				exit;
254 254
 			} else {
255 255
 				OC_Template::printErrorPage(
256 256
 					$l->t('Cannot write into "config" directory!'),
257 257
 					$l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
258
-					 [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
258
+					 [$urlGenerator->linkToDocs('admin-dir_permissions')])
259 259
 				);
260 260
 			}
261 261
 		}
@@ -270,8 +270,8 @@  discard block
 block discarded – undo
270 270
 			if (OC::$CLI) {
271 271
 				throw new Exception('Not installed');
272 272
 			} else {
273
-				$url = OC::$WEBROOT . '/index.php';
274
-				header('Location: ' . $url);
273
+				$url = OC::$WEBROOT.'/index.php';
274
+				header('Location: '.$url);
275 275
 			}
276 276
 			exit();
277 277
 		}
@@ -377,14 +377,14 @@  discard block
 block discarded – undo
377 377
 		$incompatibleShippedApps = [];
378 378
 		foreach ($incompatibleApps as $appInfo) {
379 379
 			if ($appManager->isShipped($appInfo['id'])) {
380
-				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
380
+				$incompatibleShippedApps[] = $appInfo['name'].' ('.$appInfo['id'].')';
381 381
 			}
382 382
 		}
383 383
 
384 384
 		if (!empty($incompatibleShippedApps)) {
385 385
 			$l = \OC::$server->getL10N('core');
386 386
 			$hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
387
-			throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
387
+			throw new \OC\HintException('The files of the app '.implode(', ', $incompatibleShippedApps).' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
388 388
 		}
389 389
 
390 390
 		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 	}
396 396
 
397 397
 	public static function initSession() {
398
-		if(self::$server->getRequest()->getServerProtocol() === 'https') {
398
+		if (self::$server->getRequest()->getServerProtocol() === 'https') {
399 399
 			ini_set('session.cookie_secure', true);
400 400
 		}
401 401
 
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
 		ini_set('session.cookie_httponly', 'true');
404 404
 
405 405
 		// set the cookie path to the Nextcloud directory
406
-		$cookie_path = OC::$WEBROOT ? : '/';
406
+		$cookie_path = OC::$WEBROOT ?: '/';
407 407
 		ini_set('session.cookie_path', $cookie_path);
408 408
 
409 409
 		// Let the session name be changed in the initSession Hook
@@ -437,7 +437,7 @@  discard block
 block discarded – undo
437 437
 		// session timeout
438 438
 		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
439 439
 			if (isset($_COOKIE[session_name()])) {
440
-				setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
440
+				setcookie(session_name(), null, -1, self::$WEBROOT ?: '/');
441 441
 			}
442 442
 			\OC::$server->getUserSession()->logout();
443 443
 		}
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
 				continue;
460 460
 			}
461 461
 
462
-			$file = $appPath . '/appinfo/classpath.php';
462
+			$file = $appPath.'/appinfo/classpath.php';
463 463
 			if (file_exists($file)) {
464 464
 				require_once $file;
465 465
 			}
@@ -487,14 +487,14 @@  discard block
 block discarded – undo
487 487
 
488 488
 		// Append __Host to the cookie if it meets the requirements
489 489
 		$cookiePrefix = '';
490
-		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
490
+		if ($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
491 491
 			$cookiePrefix = '__Host-';
492 492
 		}
493 493
 
494
-		foreach($policies as $policy) {
494
+		foreach ($policies as $policy) {
495 495
 			header(
496 496
 				sprintf(
497
-					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
497
+					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;'.$secureCookie.'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
498 498
 					$cookiePrefix,
499 499
 					$policy,
500 500
 					$cookieParams['path'],
@@ -525,31 +525,31 @@  discard block
 block discarded – undo
525 525
 			// OS X Finder
526 526
 			'/^WebDAVFS/',
527 527
 		];
528
-		if($request->isUserAgent($incompatibleUserAgents)) {
528
+		if ($request->isUserAgent($incompatibleUserAgents)) {
529 529
 			return;
530 530
 		}
531 531
 
532
-		if(count($_COOKIE) > 0) {
532
+		if (count($_COOKIE) > 0) {
533 533
 			$requestUri = $request->getScriptName();
534 534
 			$processingScript = explode('/', $requestUri);
535
-			$processingScript = $processingScript[count($processingScript)-1];
535
+			$processingScript = $processingScript[count($processingScript) - 1];
536 536
 
537 537
 			// index.php routes are handled in the middleware
538
-			if($processingScript === 'index.php') {
538
+			if ($processingScript === 'index.php') {
539 539
 				return;
540 540
 			}
541 541
 
542 542
 			// All other endpoints require the lax and the strict cookie
543
-			if(!$request->passesStrictCookieCheck()) {
543
+			if (!$request->passesStrictCookieCheck()) {
544 544
 				self::sendSameSiteCookies();
545 545
 				// Debug mode gets access to the resources without strict cookie
546 546
 				// due to the fact that the SabreDAV browser also lives there.
547
-				if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
547
+				if (!\OC::$server->getConfig()->getSystemValue('debug', false)) {
548 548
 					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
549 549
 					exit();
550 550
 				}
551 551
 			}
552
-		} elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
552
+		} elseif (!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
553 553
 			self::sendSameSiteCookies();
554 554
 		}
555 555
 	}
@@ -560,12 +560,12 @@  discard block
 block discarded – undo
560 560
 
561 561
 		// register autoloader
562 562
 		$loaderStart = microtime(true);
563
-		require_once __DIR__ . '/autoloader.php';
563
+		require_once __DIR__.'/autoloader.php';
564 564
 		self::$loader = new \OC\Autoloader([
565
-			OC::$SERVERROOT . '/lib/private/legacy',
565
+			OC::$SERVERROOT.'/lib/private/legacy',
566 566
 		]);
567 567
 		if (defined('PHPUNIT_RUN')) {
568
-			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
568
+			self::$loader->addValidRoot(OC::$SERVERROOT.'/tests');
569 569
 		}
570 570
 		spl_autoload_register(array(self::$loader, 'load'));
571 571
 		$loaderEnd = microtime(true);
@@ -573,12 +573,12 @@  discard block
 block discarded – undo
573 573
 		self::$CLI = (php_sapi_name() == 'cli');
574 574
 
575 575
 		// Add default composer PSR-4 autoloader
576
-		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
576
+		self::$composerAutoloader = require_once OC::$SERVERROOT.'/lib/composer/autoload.php';
577 577
 
578 578
 		try {
579 579
 			self::initPaths();
580 580
 			// setup 3rdparty autoloader
581
-			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
581
+			$vendorAutoLoad = OC::$SERVERROOT.'/3rdparty/autoload.php';
582 582
 			if (!file_exists($vendorAutoLoad)) {
583 583
 				throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
584 584
 			}
@@ -588,7 +588,7 @@  discard block
 block discarded – undo
588 588
 			if (!self::$CLI) {
589 589
 				$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
590 590
 				$protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
591
-				header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
591
+				header($protocol.' '.OC_Response::STATUS_SERVICE_UNAVAILABLE);
592 592
 			}
593 593
 			// we can't use the template error page here, because this needs the
594 594
 			// DI container which isn't available yet
@@ -606,7 +606,7 @@  discard block
 block discarded – undo
606 606
 		@ini_set('display_errors', '0');
607 607
 		@ini_set('log_errors', '1');
608 608
 
609
-		if(!date_default_timezone_set('UTC')) {
609
+		if (!date_default_timezone_set('UTC')) {
610 610
 			throw new \RuntimeException('Could not set timezone to UTC');
611 611
 		}
612 612
 
@@ -660,11 +660,11 @@  discard block
 block discarded – undo
660 660
 					// Convert l10n string into regular string for usage in database
661 661
 					$staticErrors = [];
662 662
 					foreach ($errors as $error) {
663
-						echo $error['error'] . "\n";
664
-						echo $error['hint'] . "\n\n";
663
+						echo $error['error']."\n";
664
+						echo $error['hint']."\n\n";
665 665
 						$staticErrors[] = [
666
-							'error' => (string)$error['error'],
667
-							'hint' => (string)$error['hint'],
666
+							'error' => (string) $error['error'],
667
+							'hint' => (string) $error['hint'],
668 668
 						];
669 669
 					}
670 670
 
@@ -686,7 +686,7 @@  discard block
 block discarded – undo
686 686
 		}
687 687
 		//try to set the session lifetime
688 688
 		$sessionLifeTime = self::getSessionLifeTime();
689
-		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
689
+		@ini_set('gc_maxlifetime', (string) $sessionLifeTime);
690 690
 
691 691
 		$systemConfig = \OC::$server->getSystemConfig();
692 692
 
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
 		register_shutdown_function(array($lockProvider, 'releaseAll'));
735 735
 
736 736
 		// Check whether the sample configuration has been copied
737
-		if($systemConfig->getValue('copied_sample_config', false)) {
737
+		if ($systemConfig->getValue('copied_sample_config', false)) {
738 738
 			$l = \OC::$server->getL10N('lib');
739 739
 			header('HTTP/1.1 503 Service Temporarily Unavailable');
740 740
 			header('Status: 503 Service Temporarily Unavailable');
@@ -760,11 +760,11 @@  discard block
 block discarded – undo
760 760
 		) {
761 761
 			// Allow access to CSS resources
762 762
 			$isScssRequest = false;
763
-			if(strpos($request->getPathInfo(), '/css/') === 0) {
763
+			if (strpos($request->getPathInfo(), '/css/') === 0) {
764 764
 				$isScssRequest = true;
765 765
 			}
766 766
 
767
-			if(substr($request->getRequestUri(), -11) === '/status.php') {
767
+			if (substr($request->getRequestUri(), -11) === '/status.php') {
768 768
 				OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
769 769
 				header('Status: 400 Bad Request');
770 770
 				header('Content-Type: application/json');
@@ -804,7 +804,7 @@  discard block
 block discarded – undo
804 804
 
805 805
 			// NOTE: This will be replaced to use OCP
806 806
 			$userSession = self::$server->getUserSession();
807
-			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
807
+			$userSession->listen('\OC\User', 'postLogin', function() use ($userSession) {
808 808
 				if (!defined('PHPUNIT_RUN')) {
809 809
 					// reset brute force delay for this IP address and username
810 810
 					$uid = \OC::$server->getUserSession()->getUser()->getUID();
@@ -941,12 +941,12 @@  discard block
 block discarded – undo
941 941
 		// emergency app disabling
942 942
 		if ($requestPath === '/disableapp'
943 943
 			&& $request->getMethod() === 'POST'
944
-			&& ((array)$request->getParam('appid')) !== ''
944
+			&& ((array) $request->getParam('appid')) !== ''
945 945
 		) {
946 946
 			\OCP\JSON::callCheck();
947 947
 			\OCP\JSON::checkAdminUser();
948
-			$appIds = (array)$request->getParam('appid');
949
-			foreach($appIds as $appId) {
948
+			$appIds = (array) $request->getParam('appid');
949
+			foreach ($appIds as $appId) {
950 950
 				$appId = \OC_App::cleanAppId($appId);
951 951
 				\OC::$server->getAppManager()->disableApp($appId);
952 952
 			}
@@ -961,7 +961,7 @@  discard block
 block discarded – undo
961 961
 		if (!\OCP\Util::needUpgrade()
962 962
 			&& !$systemConfig->getValue('maintenance', false)) {
963 963
 			// For logged-in users: Load everything
964
-			if(\OC::$server->getUserSession()->isLoggedIn()) {
964
+			if (\OC::$server->getUserSession()->isLoggedIn()) {
965 965
 				OC_App::loadApps();
966 966
 			} else {
967 967
 				// For guests: Load only filesystem and logging
Please login to merge, or discard this patch.
lib/private/Updater.php 2 patches
Indentation   +550 added lines, -550 removed lines patch added patch discarded remove patch
@@ -54,556 +54,556 @@
 block discarded – undo
54 54
  */
55 55
 class Updater extends BasicEmitter {
56 56
 
57
-	/** @var ILogger $log */
58
-	private $log;
59
-
60
-	/** @var IConfig */
61
-	private $config;
62
-
63
-	/** @var Checker */
64
-	private $checker;
65
-
66
-	/** @var Installer */
67
-	private $installer;
68
-
69
-	private $logLevelNames = [
70
-		0 => 'Debug',
71
-		1 => 'Info',
72
-		2 => 'Warning',
73
-		3 => 'Error',
74
-		4 => 'Fatal',
75
-	];
76
-
77
-	/**
78
-	 * @param IConfig $config
79
-	 * @param Checker $checker
80
-	 * @param ILogger $log
81
-	 * @param Installer $installer
82
-	 */
83
-	public function __construct(IConfig $config,
84
-								Checker $checker,
85
-								ILogger $log = null,
86
-								Installer $installer) {
87
-		$this->log = $log;
88
-		$this->config = $config;
89
-		$this->checker = $checker;
90
-		$this->installer = $installer;
91
-	}
92
-
93
-	/**
94
-	 * runs the update actions in maintenance mode, does not upgrade the source files
95
-	 * except the main .htaccess file
96
-	 *
97
-	 * @return bool true if the operation succeeded, false otherwise
98
-	 */
99
-	public function upgrade() {
100
-		$this->emitRepairEvents();
101
-		$this->logAllEvents();
102
-
103
-		$logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
104
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
105
-		$this->config->setSystemValue('loglevel', Util::DEBUG);
106
-
107
-		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108
-
109
-		if(!$wasMaintenanceModeEnabled) {
110
-			$this->config->setSystemValue('maintenance', true);
111
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
112
-		}
113
-
114
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
115
-		$currentVersion = implode('.', \OCP\Util::getVersion());
116
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
117
-
118
-		$success = true;
119
-		try {
120
-			$this->doUpgrade($currentVersion, $installedVersion);
121
-		} catch (HintException $exception) {
122
-			$this->log->logException($exception, ['app' => 'core']);
123
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
124
-			$success = false;
125
-		} catch (\Exception $exception) {
126
-			$this->log->logException($exception, ['app' => 'core']);
127
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
128
-			$success = false;
129
-		}
130
-
131
-		$this->emit('\OC\Updater', 'updateEnd', array($success));
132
-
133
-		if(!$wasMaintenanceModeEnabled && $success) {
134
-			$this->config->setSystemValue('maintenance', false);
135
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
136
-		} else {
137
-			$this->emit('\OC\Updater', 'maintenanceActive');
138
-		}
139
-
140
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
141
-		$this->config->setSystemValue('loglevel', $logLevel);
142
-		$this->config->setSystemValue('installed', true);
143
-
144
-		return $success;
145
-	}
146
-
147
-	/**
148
-	 * Return version from which this version is allowed to upgrade from
149
-	 *
150
-	 * @return array allowed previous versions per vendor
151
-	 */
152
-	private function getAllowedPreviousVersions() {
153
-		// this should really be a JSON file
154
-		require \OC::$SERVERROOT . '/version.php';
155
-		/** @var array $OC_VersionCanBeUpgradedFrom */
156
-		return $OC_VersionCanBeUpgradedFrom;
157
-	}
158
-
159
-	/**
160
-	 * Return vendor from which this version was published
161
-	 *
162
-	 * @return string Get the vendor
163
-	 */
164
-	private function getVendor() {
165
-		// this should really be a JSON file
166
-		require \OC::$SERVERROOT . '/version.php';
167
-		/** @var string $vendor */
168
-		return (string) $vendor;
169
-	}
170
-
171
-	/**
172
-	 * Whether an upgrade to a specified version is possible
173
-	 * @param string $oldVersion
174
-	 * @param string $newVersion
175
-	 * @param array $allowedPreviousVersions
176
-	 * @return bool
177
-	 */
178
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
179
-		$version = explode('.', $oldVersion);
180
-		$majorMinor = $version[0] . '.' . $version[1];
181
-
182
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
183
-
184
-		// Vendor was not set correctly on install, so we have to white-list known versions
185
-		if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
186
-			$currentVendor = 'owncloud';
187
-		}
188
-
189
-		if ($currentVendor === 'nextcloud') {
190
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
191
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
192
-					$this->config->getSystemValue('debug', false));
193
-		}
194
-
195
-		// Check if the instance can be migrated
196
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
197
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
198
-	}
199
-
200
-	/**
201
-	 * runs the update actions in maintenance mode, does not upgrade the source files
202
-	 * except the main .htaccess file
203
-	 *
204
-	 * @param string $currentVersion current version to upgrade to
205
-	 * @param string $installedVersion previous version from which to upgrade from
206
-	 *
207
-	 * @throws \Exception
208
-	 */
209
-	private function doUpgrade($currentVersion, $installedVersion) {
210
-		// Stop update if the update is over several major versions
211
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
212
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
213
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
214
-		}
215
-
216
-		// Update .htaccess files
217
-		try {
218
-			Setup::updateHtaccess();
219
-			Setup::protectDataDirectory();
220
-		} catch (\Exception $e) {
221
-			throw new \Exception($e->getMessage());
222
-		}
223
-
224
-		// create empty file in data dir, so we can later find
225
-		// out that this is indeed an ownCloud data directory
226
-		// (in case it didn't exist before)
227
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
228
-
229
-		// pre-upgrade repairs
230
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
231
-		$repair->run();
232
-
233
-		$this->doCoreUpgrade();
234
-
235
-		try {
236
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
237
-			Setup::installBackgroundJobs();
238
-		} catch (\Exception $e) {
239
-			throw new \Exception($e->getMessage());
240
-		}
241
-
242
-		// update all shipped apps
243
-		$this->checkAppsRequirements();
244
-		$this->doAppUpgrade();
245
-
246
-		// Update the appfetchers version so it downloads the correct list from the appstore
247
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
248
-
249
-		// upgrade appstore apps
250
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
251
-
252
-		// install new shipped apps on upgrade
253
-		OC_App::loadApps('authentication');
254
-		$errors = Installer::installShippedApps(true);
255
-		foreach ($errors as $appId => $exception) {
256
-			/** @var \Exception $exception */
257
-			$this->log->logException($exception, ['app' => $appId]);
258
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
259
-		}
260
-
261
-		// post-upgrade repairs
262
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
263
-		$repair->run();
264
-
265
-		//Invalidate update feed
266
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
267
-
268
-		// Check for code integrity if not disabled
269
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
270
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
271
-			$this->checker->runInstanceVerification();
272
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
273
-		}
274
-
275
-		// only set the final version if everything went well
276
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
277
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
278
-	}
279
-
280
-	protected function doCoreUpgrade() {
281
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
282
-
283
-		// execute core migrations
284
-		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
285
-		$ms->migrate();
286
-
287
-		$this->emit('\OC\Updater', 'dbUpgrade');
288
-	}
289
-
290
-	/**
291
-	 * @param string $version the oc version to check app compatibility with
292
-	 */
293
-	protected function checkAppUpgrade($version) {
294
-		$apps = \OC_App::getEnabledApps();
295
-		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
296
-
297
-		$appManager = \OC::$server->getAppManager();
298
-		foreach ($apps as $appId) {
299
-			$info = \OC_App::getAppInfo($appId);
300
-			$compatible = \OC_App::isAppCompatible($version, $info);
301
-			$isShipped = $appManager->isShipped($appId);
302
-
303
-			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
304
-				/**
305
-				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
306
-				 * are not possible anymore within it. - Consider this when touching the code.
307
-				 * @link https://github.com/owncloud/core/issues/10980
308
-				 * @see \OC_App::updateApp
309
-				 */
310
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
311
-					$this->includePreUpdate($appId);
312
-				}
313
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
314
-					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
315
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
316
-				}
317
-			}
318
-		}
319
-
320
-		$this->emit('\OC\Updater', 'appUpgradeCheck');
321
-	}
322
-
323
-	/**
324
-	 * Includes the pre-update file. Done here to prevent namespace mixups.
325
-	 * @param string $appId
326
-	 */
327
-	private function includePreUpdate($appId) {
328
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
329
-	}
330
-
331
-	/**
332
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
333
-	 * (types authentication, filesystem, logging, in that order) afterwards.
334
-	 *
335
-	 * @throws NeedsUpdateException
336
-	 */
337
-	protected function doAppUpgrade() {
338
-		$apps = \OC_App::getEnabledApps();
339
-		$priorityTypes = array('authentication', 'filesystem', 'logging');
340
-		$pseudoOtherType = 'other';
341
-		$stacks = array($pseudoOtherType => array());
342
-
343
-		foreach ($apps as $appId) {
344
-			$priorityType = false;
345
-			foreach ($priorityTypes as $type) {
346
-				if(!isset($stacks[$type])) {
347
-					$stacks[$type] = array();
348
-				}
349
-				if (\OC_App::isType($appId, $type)) {
350
-					$stacks[$type][] = $appId;
351
-					$priorityType = true;
352
-					break;
353
-				}
354
-			}
355
-			if (!$priorityType) {
356
-				$stacks[$pseudoOtherType][] = $appId;
357
-			}
358
-		}
359
-		foreach ($stacks as $type => $stack) {
360
-			foreach ($stack as $appId) {
361
-				if (\OC_App::shouldUpgrade($appId)) {
362
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
363
-					\OC_App::updateApp($appId);
364
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
365
-				}
366
-				if($type !== $pseudoOtherType) {
367
-					// load authentication, filesystem and logging apps after
368
-					// upgrading them. Other apps my need to rely on modifying
369
-					// user and/or filesystem aspects.
370
-					\OC_App::loadApp($appId);
371
-				}
372
-			}
373
-		}
374
-	}
375
-
376
-	/**
377
-	 * check if the current enabled apps are compatible with the current
378
-	 * ownCloud version. disable them if not.
379
-	 * This is important if you upgrade ownCloud and have non ported 3rd
380
-	 * party apps installed.
381
-	 *
382
-	 * @return array
383
-	 * @throws \Exception
384
-	 */
385
-	private function checkAppsRequirements() {
386
-		$isCoreUpgrade = $this->isCodeUpgrade();
387
-		$apps = OC_App::getEnabledApps();
388
-		$version = Util::getVersion();
389
-		$disabledApps = [];
390
-		$appManager = \OC::$server->getAppManager();
391
-		foreach ($apps as $app) {
392
-			// check if the app is compatible with this version of ownCloud
393
-			$info = OC_App::getAppInfo($app);
394
-			if(!OC_App::isAppCompatible($version, $info)) {
395
-				if ($appManager->isShipped($app)) {
396
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
397
-				}
398
-				\OC::$server->getAppManager()->disableApp($app);
399
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
400
-			}
401
-			// no need to disable any app in case this is a non-core upgrade
402
-			if (!$isCoreUpgrade) {
403
-				continue;
404
-			}
405
-			// shipped apps will remain enabled
406
-			if ($appManager->isShipped($app)) {
407
-				continue;
408
-			}
409
-			// authentication and session apps will remain enabled as well
410
-			if (OC_App::isType($app, ['session', 'authentication'])) {
411
-				continue;
412
-			}
413
-		}
414
-		return $disabledApps;
415
-	}
416
-
417
-	/**
418
-	 * @return bool
419
-	 */
420
-	private function isCodeUpgrade() {
421
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
422
-		$currentVersion = implode('.', Util::getVersion());
423
-		if (version_compare($currentVersion, $installedVersion, '>')) {
424
-			return true;
425
-		}
426
-		return false;
427
-	}
428
-
429
-	/**
430
-	 * @param array $disabledApps
431
-	 * @throws \Exception
432
-	 */
433
-	private function upgradeAppStoreApps(array $disabledApps) {
434
-		foreach($disabledApps as $app) {
435
-			try {
436
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
437
-				if ($this->installer->isUpdateAvailable($app)) {
438
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
439
-					$this->installer->updateAppstoreApp($app);
440
-				}
441
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
442
-			} catch (\Exception $ex) {
443
-				$this->log->logException($ex, ['app' => 'core']);
444
-			}
445
-		}
446
-	}
447
-
448
-	/**
449
-	 * Forward messages emitted by the repair routine
450
-	 */
451
-	private function emitRepairEvents() {
452
-		$dispatcher = \OC::$server->getEventDispatcher();
453
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
454
-			if ($event instanceof GenericEvent) {
455
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
456
-			}
457
-		});
458
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
459
-			if ($event instanceof GenericEvent) {
460
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
461
-			}
462
-		});
463
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
464
-			if ($event instanceof GenericEvent) {
465
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
466
-			}
467
-		});
468
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
469
-			if ($event instanceof GenericEvent) {
470
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
471
-			}
472
-		});
473
-	}
474
-
475
-	private function logAllEvents() {
476
-		$log = $this->log;
477
-
478
-		$dispatcher = \OC::$server->getEventDispatcher();
479
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
480
-			if (!$event instanceof GenericEvent) {
481
-				return;
482
-			}
483
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
484
-		});
485
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
486
-			if (!$event instanceof GenericEvent) {
487
-				return;
488
-			}
489
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
490
-		});
491
-
492
-		$repairListener = function($event) use ($log) {
493
-			if (!$event instanceof GenericEvent) {
494
-				return;
495
-			}
496
-			switch ($event->getSubject()) {
497
-				case '\OC\Repair::startProgress':
498
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
499
-					break;
500
-				case '\OC\Repair::advance':
501
-					$desc = $event->getArgument(1);
502
-					if (empty($desc)) {
503
-						$desc = '';
504
-					}
505
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
506
-
507
-					break;
508
-				case '\OC\Repair::finishProgress':
509
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
510
-					break;
511
-				case '\OC\Repair::step':
512
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
513
-					break;
514
-				case '\OC\Repair::info':
515
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
516
-					break;
517
-				case '\OC\Repair::warning':
518
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
519
-					break;
520
-				case '\OC\Repair::error':
521
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
522
-					break;
523
-			}
524
-		};
525
-
526
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
527
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
528
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
529
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
530
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
531
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
532
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
533
-
534
-
535
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
536
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
537
-		});
538
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
539
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
540
-		});
541
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
542
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
543
-		});
544
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
545
-			if ($success) {
546
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
547
-			} else {
548
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
549
-			}
550
-		});
551
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
552
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
553
-		});
554
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
555
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
556
-		});
557
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
558
-			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
559
-		});
560
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
561
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
562
-		});
563
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
564
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
565
-		});
566
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
567
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
568
-		});
569
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
570
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
571
-		});
572
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
573
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
574
-		});
575
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
576
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
577
-		});
578
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
579
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
580
-		});
581
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
582
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
583
-		});
584
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
585
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
586
-		});
587
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
588
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
589
-		});
590
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
591
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
592
-		});
593
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
594
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
595
-		});
596
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
597
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
598
-		});
599
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
600
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
601
-		});
602
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
603
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
604
-		});
605
-
606
-	}
57
+    /** @var ILogger $log */
58
+    private $log;
59
+
60
+    /** @var IConfig */
61
+    private $config;
62
+
63
+    /** @var Checker */
64
+    private $checker;
65
+
66
+    /** @var Installer */
67
+    private $installer;
68
+
69
+    private $logLevelNames = [
70
+        0 => 'Debug',
71
+        1 => 'Info',
72
+        2 => 'Warning',
73
+        3 => 'Error',
74
+        4 => 'Fatal',
75
+    ];
76
+
77
+    /**
78
+     * @param IConfig $config
79
+     * @param Checker $checker
80
+     * @param ILogger $log
81
+     * @param Installer $installer
82
+     */
83
+    public function __construct(IConfig $config,
84
+                                Checker $checker,
85
+                                ILogger $log = null,
86
+                                Installer $installer) {
87
+        $this->log = $log;
88
+        $this->config = $config;
89
+        $this->checker = $checker;
90
+        $this->installer = $installer;
91
+    }
92
+
93
+    /**
94
+     * runs the update actions in maintenance mode, does not upgrade the source files
95
+     * except the main .htaccess file
96
+     *
97
+     * @return bool true if the operation succeeded, false otherwise
98
+     */
99
+    public function upgrade() {
100
+        $this->emitRepairEvents();
101
+        $this->logAllEvents();
102
+
103
+        $logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
104
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
105
+        $this->config->setSystemValue('loglevel', Util::DEBUG);
106
+
107
+        $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108
+
109
+        if(!$wasMaintenanceModeEnabled) {
110
+            $this->config->setSystemValue('maintenance', true);
111
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
112
+        }
113
+
114
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
115
+        $currentVersion = implode('.', \OCP\Util::getVersion());
116
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
117
+
118
+        $success = true;
119
+        try {
120
+            $this->doUpgrade($currentVersion, $installedVersion);
121
+        } catch (HintException $exception) {
122
+            $this->log->logException($exception, ['app' => 'core']);
123
+            $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
124
+            $success = false;
125
+        } catch (\Exception $exception) {
126
+            $this->log->logException($exception, ['app' => 'core']);
127
+            $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
128
+            $success = false;
129
+        }
130
+
131
+        $this->emit('\OC\Updater', 'updateEnd', array($success));
132
+
133
+        if(!$wasMaintenanceModeEnabled && $success) {
134
+            $this->config->setSystemValue('maintenance', false);
135
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
136
+        } else {
137
+            $this->emit('\OC\Updater', 'maintenanceActive');
138
+        }
139
+
140
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
141
+        $this->config->setSystemValue('loglevel', $logLevel);
142
+        $this->config->setSystemValue('installed', true);
143
+
144
+        return $success;
145
+    }
146
+
147
+    /**
148
+     * Return version from which this version is allowed to upgrade from
149
+     *
150
+     * @return array allowed previous versions per vendor
151
+     */
152
+    private function getAllowedPreviousVersions() {
153
+        // this should really be a JSON file
154
+        require \OC::$SERVERROOT . '/version.php';
155
+        /** @var array $OC_VersionCanBeUpgradedFrom */
156
+        return $OC_VersionCanBeUpgradedFrom;
157
+    }
158
+
159
+    /**
160
+     * Return vendor from which this version was published
161
+     *
162
+     * @return string Get the vendor
163
+     */
164
+    private function getVendor() {
165
+        // this should really be a JSON file
166
+        require \OC::$SERVERROOT . '/version.php';
167
+        /** @var string $vendor */
168
+        return (string) $vendor;
169
+    }
170
+
171
+    /**
172
+     * Whether an upgrade to a specified version is possible
173
+     * @param string $oldVersion
174
+     * @param string $newVersion
175
+     * @param array $allowedPreviousVersions
176
+     * @return bool
177
+     */
178
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
179
+        $version = explode('.', $oldVersion);
180
+        $majorMinor = $version[0] . '.' . $version[1];
181
+
182
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
183
+
184
+        // Vendor was not set correctly on install, so we have to white-list known versions
185
+        if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
186
+            $currentVendor = 'owncloud';
187
+        }
188
+
189
+        if ($currentVendor === 'nextcloud') {
190
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
191
+                && (version_compare($oldVersion, $newVersion, '<=') ||
192
+                    $this->config->getSystemValue('debug', false));
193
+        }
194
+
195
+        // Check if the instance can be migrated
196
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
197
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
198
+    }
199
+
200
+    /**
201
+     * runs the update actions in maintenance mode, does not upgrade the source files
202
+     * except the main .htaccess file
203
+     *
204
+     * @param string $currentVersion current version to upgrade to
205
+     * @param string $installedVersion previous version from which to upgrade from
206
+     *
207
+     * @throws \Exception
208
+     */
209
+    private function doUpgrade($currentVersion, $installedVersion) {
210
+        // Stop update if the update is over several major versions
211
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
212
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
213
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
214
+        }
215
+
216
+        // Update .htaccess files
217
+        try {
218
+            Setup::updateHtaccess();
219
+            Setup::protectDataDirectory();
220
+        } catch (\Exception $e) {
221
+            throw new \Exception($e->getMessage());
222
+        }
223
+
224
+        // create empty file in data dir, so we can later find
225
+        // out that this is indeed an ownCloud data directory
226
+        // (in case it didn't exist before)
227
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
228
+
229
+        // pre-upgrade repairs
230
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
231
+        $repair->run();
232
+
233
+        $this->doCoreUpgrade();
234
+
235
+        try {
236
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
237
+            Setup::installBackgroundJobs();
238
+        } catch (\Exception $e) {
239
+            throw new \Exception($e->getMessage());
240
+        }
241
+
242
+        // update all shipped apps
243
+        $this->checkAppsRequirements();
244
+        $this->doAppUpgrade();
245
+
246
+        // Update the appfetchers version so it downloads the correct list from the appstore
247
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
248
+
249
+        // upgrade appstore apps
250
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
251
+
252
+        // install new shipped apps on upgrade
253
+        OC_App::loadApps('authentication');
254
+        $errors = Installer::installShippedApps(true);
255
+        foreach ($errors as $appId => $exception) {
256
+            /** @var \Exception $exception */
257
+            $this->log->logException($exception, ['app' => $appId]);
258
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
259
+        }
260
+
261
+        // post-upgrade repairs
262
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
263
+        $repair->run();
264
+
265
+        //Invalidate update feed
266
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
267
+
268
+        // Check for code integrity if not disabled
269
+        if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
270
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
271
+            $this->checker->runInstanceVerification();
272
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
273
+        }
274
+
275
+        // only set the final version if everything went well
276
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
277
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
278
+    }
279
+
280
+    protected function doCoreUpgrade() {
281
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
282
+
283
+        // execute core migrations
284
+        $ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
285
+        $ms->migrate();
286
+
287
+        $this->emit('\OC\Updater', 'dbUpgrade');
288
+    }
289
+
290
+    /**
291
+     * @param string $version the oc version to check app compatibility with
292
+     */
293
+    protected function checkAppUpgrade($version) {
294
+        $apps = \OC_App::getEnabledApps();
295
+        $this->emit('\OC\Updater', 'appUpgradeCheckBefore');
296
+
297
+        $appManager = \OC::$server->getAppManager();
298
+        foreach ($apps as $appId) {
299
+            $info = \OC_App::getAppInfo($appId);
300
+            $compatible = \OC_App::isAppCompatible($version, $info);
301
+            $isShipped = $appManager->isShipped($appId);
302
+
303
+            if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
304
+                /**
305
+                 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
306
+                 * are not possible anymore within it. - Consider this when touching the code.
307
+                 * @link https://github.com/owncloud/core/issues/10980
308
+                 * @see \OC_App::updateApp
309
+                 */
310
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
311
+                    $this->includePreUpdate($appId);
312
+                }
313
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
314
+                    $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
315
+                    \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
316
+                }
317
+            }
318
+        }
319
+
320
+        $this->emit('\OC\Updater', 'appUpgradeCheck');
321
+    }
322
+
323
+    /**
324
+     * Includes the pre-update file. Done here to prevent namespace mixups.
325
+     * @param string $appId
326
+     */
327
+    private function includePreUpdate($appId) {
328
+        include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
329
+    }
330
+
331
+    /**
332
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
333
+     * (types authentication, filesystem, logging, in that order) afterwards.
334
+     *
335
+     * @throws NeedsUpdateException
336
+     */
337
+    protected function doAppUpgrade() {
338
+        $apps = \OC_App::getEnabledApps();
339
+        $priorityTypes = array('authentication', 'filesystem', 'logging');
340
+        $pseudoOtherType = 'other';
341
+        $stacks = array($pseudoOtherType => array());
342
+
343
+        foreach ($apps as $appId) {
344
+            $priorityType = false;
345
+            foreach ($priorityTypes as $type) {
346
+                if(!isset($stacks[$type])) {
347
+                    $stacks[$type] = array();
348
+                }
349
+                if (\OC_App::isType($appId, $type)) {
350
+                    $stacks[$type][] = $appId;
351
+                    $priorityType = true;
352
+                    break;
353
+                }
354
+            }
355
+            if (!$priorityType) {
356
+                $stacks[$pseudoOtherType][] = $appId;
357
+            }
358
+        }
359
+        foreach ($stacks as $type => $stack) {
360
+            foreach ($stack as $appId) {
361
+                if (\OC_App::shouldUpgrade($appId)) {
362
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
363
+                    \OC_App::updateApp($appId);
364
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
365
+                }
366
+                if($type !== $pseudoOtherType) {
367
+                    // load authentication, filesystem and logging apps after
368
+                    // upgrading them. Other apps my need to rely on modifying
369
+                    // user and/or filesystem aspects.
370
+                    \OC_App::loadApp($appId);
371
+                }
372
+            }
373
+        }
374
+    }
375
+
376
+    /**
377
+     * check if the current enabled apps are compatible with the current
378
+     * ownCloud version. disable them if not.
379
+     * This is important if you upgrade ownCloud and have non ported 3rd
380
+     * party apps installed.
381
+     *
382
+     * @return array
383
+     * @throws \Exception
384
+     */
385
+    private function checkAppsRequirements() {
386
+        $isCoreUpgrade = $this->isCodeUpgrade();
387
+        $apps = OC_App::getEnabledApps();
388
+        $version = Util::getVersion();
389
+        $disabledApps = [];
390
+        $appManager = \OC::$server->getAppManager();
391
+        foreach ($apps as $app) {
392
+            // check if the app is compatible with this version of ownCloud
393
+            $info = OC_App::getAppInfo($app);
394
+            if(!OC_App::isAppCompatible($version, $info)) {
395
+                if ($appManager->isShipped($app)) {
396
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
397
+                }
398
+                \OC::$server->getAppManager()->disableApp($app);
399
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
400
+            }
401
+            // no need to disable any app in case this is a non-core upgrade
402
+            if (!$isCoreUpgrade) {
403
+                continue;
404
+            }
405
+            // shipped apps will remain enabled
406
+            if ($appManager->isShipped($app)) {
407
+                continue;
408
+            }
409
+            // authentication and session apps will remain enabled as well
410
+            if (OC_App::isType($app, ['session', 'authentication'])) {
411
+                continue;
412
+            }
413
+        }
414
+        return $disabledApps;
415
+    }
416
+
417
+    /**
418
+     * @return bool
419
+     */
420
+    private function isCodeUpgrade() {
421
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
422
+        $currentVersion = implode('.', Util::getVersion());
423
+        if (version_compare($currentVersion, $installedVersion, '>')) {
424
+            return true;
425
+        }
426
+        return false;
427
+    }
428
+
429
+    /**
430
+     * @param array $disabledApps
431
+     * @throws \Exception
432
+     */
433
+    private function upgradeAppStoreApps(array $disabledApps) {
434
+        foreach($disabledApps as $app) {
435
+            try {
436
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
437
+                if ($this->installer->isUpdateAvailable($app)) {
438
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
439
+                    $this->installer->updateAppstoreApp($app);
440
+                }
441
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
442
+            } catch (\Exception $ex) {
443
+                $this->log->logException($ex, ['app' => 'core']);
444
+            }
445
+        }
446
+    }
447
+
448
+    /**
449
+     * Forward messages emitted by the repair routine
450
+     */
451
+    private function emitRepairEvents() {
452
+        $dispatcher = \OC::$server->getEventDispatcher();
453
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
454
+            if ($event instanceof GenericEvent) {
455
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
456
+            }
457
+        });
458
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
459
+            if ($event instanceof GenericEvent) {
460
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
461
+            }
462
+        });
463
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
464
+            if ($event instanceof GenericEvent) {
465
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
466
+            }
467
+        });
468
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
469
+            if ($event instanceof GenericEvent) {
470
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
471
+            }
472
+        });
473
+    }
474
+
475
+    private function logAllEvents() {
476
+        $log = $this->log;
477
+
478
+        $dispatcher = \OC::$server->getEventDispatcher();
479
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
480
+            if (!$event instanceof GenericEvent) {
481
+                return;
482
+            }
483
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
484
+        });
485
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
486
+            if (!$event instanceof GenericEvent) {
487
+                return;
488
+            }
489
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
490
+        });
491
+
492
+        $repairListener = function($event) use ($log) {
493
+            if (!$event instanceof GenericEvent) {
494
+                return;
495
+            }
496
+            switch ($event->getSubject()) {
497
+                case '\OC\Repair::startProgress':
498
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
499
+                    break;
500
+                case '\OC\Repair::advance':
501
+                    $desc = $event->getArgument(1);
502
+                    if (empty($desc)) {
503
+                        $desc = '';
504
+                    }
505
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
506
+
507
+                    break;
508
+                case '\OC\Repair::finishProgress':
509
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
510
+                    break;
511
+                case '\OC\Repair::step':
512
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
513
+                    break;
514
+                case '\OC\Repair::info':
515
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
516
+                    break;
517
+                case '\OC\Repair::warning':
518
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
519
+                    break;
520
+                case '\OC\Repair::error':
521
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
522
+                    break;
523
+            }
524
+        };
525
+
526
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
527
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
528
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
529
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
530
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
531
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
532
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
533
+
534
+
535
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
536
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
537
+        });
538
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
539
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
540
+        });
541
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
542
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
543
+        });
544
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
545
+            if ($success) {
546
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
547
+            } else {
548
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
549
+            }
550
+        });
551
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
552
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
553
+        });
554
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
555
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
556
+        });
557
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
558
+            $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
559
+        });
560
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
561
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
562
+        });
563
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
564
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
565
+        });
566
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
567
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
568
+        });
569
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
570
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
571
+        });
572
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
573
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
574
+        });
575
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
576
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
577
+        });
578
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
579
+            $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
580
+        });
581
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
582
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
583
+        });
584
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
585
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
586
+        });
587
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
588
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
589
+        });
590
+        $this->listen('\OC\Updater', 'failure', function ($message) use($log) {
591
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
592
+        });
593
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
594
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
595
+        });
596
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
597
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
598
+        });
599
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
600
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
601
+        });
602
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
603
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
604
+        });
605
+
606
+    }
607 607
 
608 608
 }
609 609
 
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -101,43 +101,43 @@  discard block
 block discarded – undo
101 101
 		$this->logAllEvents();
102 102
 
103 103
 		$logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
104
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
104
+		$this->emit('\OC\Updater', 'setDebugLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
105 105
 		$this->config->setSystemValue('loglevel', Util::DEBUG);
106 106
 
107 107
 		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108 108
 
109
-		if(!$wasMaintenanceModeEnabled) {
109
+		if (!$wasMaintenanceModeEnabled) {
110 110
 			$this->config->setSystemValue('maintenance', true);
111 111
 			$this->emit('\OC\Updater', 'maintenanceEnabled');
112 112
 		}
113 113
 
114 114
 		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
115 115
 		$currentVersion = implode('.', \OCP\Util::getVersion());
116
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
116
+		$this->log->debug('starting upgrade from '.$installedVersion.' to '.$currentVersion, array('app' => 'core'));
117 117
 
118 118
 		$success = true;
119 119
 		try {
120 120
 			$this->doUpgrade($currentVersion, $installedVersion);
121 121
 		} catch (HintException $exception) {
122 122
 			$this->log->logException($exception, ['app' => 'core']);
123
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
123
+			$this->emit('\OC\Updater', 'failure', array($exception->getMessage().': '.$exception->getHint()));
124 124
 			$success = false;
125 125
 		} catch (\Exception $exception) {
126 126
 			$this->log->logException($exception, ['app' => 'core']);
127
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
127
+			$this->emit('\OC\Updater', 'failure', array(get_class($exception).': '.$exception->getMessage()));
128 128
 			$success = false;
129 129
 		}
130 130
 
131 131
 		$this->emit('\OC\Updater', 'updateEnd', array($success));
132 132
 
133
-		if(!$wasMaintenanceModeEnabled && $success) {
133
+		if (!$wasMaintenanceModeEnabled && $success) {
134 134
 			$this->config->setSystemValue('maintenance', false);
135 135
 			$this->emit('\OC\Updater', 'maintenanceDisabled');
136 136
 		} else {
137 137
 			$this->emit('\OC\Updater', 'maintenanceActive');
138 138
 		}
139 139
 
140
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
140
+		$this->emit('\OC\Updater', 'resetLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
141 141
 		$this->config->setSystemValue('loglevel', $logLevel);
142 142
 		$this->config->setSystemValue('installed', true);
143 143
 
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
 	 */
152 152
 	private function getAllowedPreviousVersions() {
153 153
 		// this should really be a JSON file
154
-		require \OC::$SERVERROOT . '/version.php';
154
+		require \OC::$SERVERROOT.'/version.php';
155 155
 		/** @var array $OC_VersionCanBeUpgradedFrom */
156 156
 		return $OC_VersionCanBeUpgradedFrom;
157 157
 	}
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 	 */
164 164
 	private function getVendor() {
165 165
 		// this should really be a JSON file
166
-		require \OC::$SERVERROOT . '/version.php';
166
+		require \OC::$SERVERROOT.'/version.php';
167 167
 		/** @var string $vendor */
168 168
 		return (string) $vendor;
169 169
 	}
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 	 */
178 178
 	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
179 179
 		$version = explode('.', $oldVersion);
180
-		$majorMinor = $version[0] . '.' . $version[1];
180
+		$majorMinor = $version[0].'.'.$version[1];
181 181
 
182 182
 		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
183 183
 
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 		// create empty file in data dir, so we can later find
225 225
 		// out that this is indeed an ownCloud data directory
226 226
 		// (in case it didn't exist before)
227
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
227
+		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
228 228
 
229 229
 		// pre-upgrade repairs
230 230
 		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
 		foreach ($errors as $appId => $exception) {
256 256
 			/** @var \Exception $exception */
257 257
 			$this->log->logException($exception, ['app' => $appId]);
258
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
258
+			$this->emit('\OC\Updater', 'failure', [$appId.': '.$exception->getMessage()]);
259 259
 		}
260 260
 
261 261
 		// post-upgrade repairs
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
 		$this->config->setAppValue('core', 'lastupdatedat', 0);
267 267
 
268 268
 		// Check for code integrity if not disabled
269
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
269
+		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
270 270
 			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
271 271
 			$this->checker->runInstanceVerification();
272 272
 			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
@@ -307,12 +307,12 @@  discard block
 block discarded – undo
307 307
 				 * @link https://github.com/owncloud/core/issues/10980
308 308
 				 * @see \OC_App::updateApp
309 309
 				 */
310
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
310
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/preupdate.php')) {
311 311
 					$this->includePreUpdate($appId);
312 312
 				}
313
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
313
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/database.xml')) {
314 314
 					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
315
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
315
+					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId).'/appinfo/database.xml');
316 316
 				}
317 317
 			}
318 318
 		}
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
 	 * @param string $appId
326 326
 	 */
327 327
 	private function includePreUpdate($appId) {
328
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
328
+		include \OC_App::getAppPath($appId).'/appinfo/preupdate.php';
329 329
 	}
330 330
 
331 331
 	/**
@@ -343,7 +343,7 @@  discard block
 block discarded – undo
343 343
 		foreach ($apps as $appId) {
344 344
 			$priorityType = false;
345 345
 			foreach ($priorityTypes as $type) {
346
-				if(!isset($stacks[$type])) {
346
+				if (!isset($stacks[$type])) {
347 347
 					$stacks[$type] = array();
348 348
 				}
349 349
 				if (\OC_App::isType($appId, $type)) {
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
 					\OC_App::updateApp($appId);
364 364
 					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
365 365
 				}
366
-				if($type !== $pseudoOtherType) {
366
+				if ($type !== $pseudoOtherType) {
367 367
 					// load authentication, filesystem and logging apps after
368 368
 					// upgrading them. Other apps my need to rely on modifying
369 369
 					// user and/or filesystem aspects.
@@ -391,9 +391,9 @@  discard block
 block discarded – undo
391 391
 		foreach ($apps as $app) {
392 392
 			// check if the app is compatible with this version of ownCloud
393 393
 			$info = OC_App::getAppInfo($app);
394
-			if(!OC_App::isAppCompatible($version, $info)) {
394
+			if (!OC_App::isAppCompatible($version, $info)) {
395 395
 				if ($appManager->isShipped($app)) {
396
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
396
+					throw new \UnexpectedValueException('The files of the app "'.$app.'" were not correctly replaced before running the update');
397 397
 				}
398 398
 				\OC::$server->getAppManager()->disableApp($app);
399 399
 				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
@@ -431,7 +431,7 @@  discard block
 block discarded – undo
431 431
 	 * @throws \Exception
432 432
 	 */
433 433
 	private function upgradeAppStoreApps(array $disabledApps) {
434
-		foreach($disabledApps as $app) {
434
+		foreach ($disabledApps as $app) {
435 435
 			try {
436 436
 				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
437 437
 				if ($this->installer->isUpdateAvailable($app)) {
@@ -450,22 +450,22 @@  discard block
 block discarded – undo
450 450
 	 */
451 451
 	private function emitRepairEvents() {
452 452
 		$dispatcher = \OC::$server->getEventDispatcher();
453
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
453
+		$dispatcher->addListener('\OC\Repair::warning', function($event) {
454 454
 			if ($event instanceof GenericEvent) {
455 455
 				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
456 456
 			}
457 457
 		});
458
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
458
+		$dispatcher->addListener('\OC\Repair::error', function($event) {
459 459
 			if ($event instanceof GenericEvent) {
460 460
 				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
461 461
 			}
462 462
 		});
463
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
463
+		$dispatcher->addListener('\OC\Repair::info', function($event) {
464 464
 			if ($event instanceof GenericEvent) {
465 465
 				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
466 466
 			}
467 467
 		});
468
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
468
+		$dispatcher->addListener('\OC\Repair::step', function($event) {
469 469
 			if ($event instanceof GenericEvent) {
470 470
 				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
471 471
 			}
@@ -480,13 +480,13 @@  discard block
 block discarded – undo
480 480
 			if (!$event instanceof GenericEvent) {
481 481
 				return;
482 482
 			}
483
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
483
+			$log->info('\OC\DB\Migrator::executeSql: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
484 484
 		});
485 485
 		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
486 486
 			if (!$event instanceof GenericEvent) {
487 487
 				return;
488 488
 			}
489
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
489
+			$log->info('\OC\DB\Migrator::checkTable: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
490 490
 		});
491 491
 
492 492
 		$repairListener = function($event) use ($log) {
@@ -495,30 +495,30 @@  discard block
 block discarded – undo
495 495
 			}
496 496
 			switch ($event->getSubject()) {
497 497
 				case '\OC\Repair::startProgress':
498
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
498
+					$log->info('\OC\Repair::startProgress: Starting ... '.$event->getArgument(1).' ('.$event->getArgument(0).')', ['app' => 'updater']);
499 499
 					break;
500 500
 				case '\OC\Repair::advance':
501 501
 					$desc = $event->getArgument(1);
502 502
 					if (empty($desc)) {
503 503
 						$desc = '';
504 504
 					}
505
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
505
+					$log->info('\OC\Repair::advance: '.$desc.' ('.$event->getArgument(0).')', ['app' => 'updater']);
506 506
 
507 507
 					break;
508 508
 				case '\OC\Repair::finishProgress':
509 509
 					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
510 510
 					break;
511 511
 				case '\OC\Repair::step':
512
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
512
+					$log->info('\OC\Repair::step: Repair step: '.$event->getArgument(0), ['app' => 'updater']);
513 513
 					break;
514 514
 				case '\OC\Repair::info':
515
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
515
+					$log->info('\OC\Repair::info: Repair info: '.$event->getArgument(0), ['app' => 'updater']);
516 516
 					break;
517 517
 				case '\OC\Repair::warning':
518
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
518
+					$log->warning('\OC\Repair::warning: Repair warning: '.$event->getArgument(0), ['app' => 'updater']);
519 519
 					break;
520 520
 				case '\OC\Repair::error':
521
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
521
+					$log->error('\OC\Repair::error: Repair error: '.$event->getArgument(0), ['app' => 'updater']);
522 522
 					break;
523 523
 			}
524 524
 		};
@@ -532,74 +532,74 @@  discard block
 block discarded – undo
532 532
 		$dispatcher->addListener('\OC\Repair::error', $repairListener);
533 533
 
534 534
 
535
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
535
+		$this->listen('\OC\Updater', 'maintenanceEnabled', function() use($log) {
536 536
 			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
537 537
 		});
538
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
538
+		$this->listen('\OC\Updater', 'maintenanceDisabled', function() use($log) {
539 539
 			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
540 540
 		});
541
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
541
+		$this->listen('\OC\Updater', 'maintenanceActive', function() use($log) {
542 542
 			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
543 543
 		});
544
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
544
+		$this->listen('\OC\Updater', 'updateEnd', function($success) use($log) {
545 545
 			if ($success) {
546 546
 				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
547 547
 			} else {
548 548
 				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
549 549
 			}
550 550
 		});
551
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
551
+		$this->listen('\OC\Updater', 'dbUpgradeBefore', function() use($log) {
552 552
 			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
553 553
 		});
554
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
554
+		$this->listen('\OC\Updater', 'dbUpgrade', function() use($log) {
555 555
 			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
556 556
 		});
557
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
557
+		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function() use($log) {
558 558
 			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
559 559
 		});
560
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
560
+		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function() use($log) {
561 561
 			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
562 562
 		});
563
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
564
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
563
+		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use($log) {
564
+			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: '.$app, ['app' => 'updater']);
565 565
 		});
566
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
567
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
566
+		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use($log) {
567
+			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "'.$app.'" in appstore', ['app' => 'updater']);
568 568
 		});
569
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
570
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
569
+		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use($log) {
570
+			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "'.$app.'" from appstore', ['app' => 'updater']);
571 571
 		});
572
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
573
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
572
+		$this->listen('\OC\Updater', 'checkAppStoreApp', function($app) use($log) {
573
+			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "'.$app.'" in appstore', ['app' => 'updater']);
574 574
 		});
575
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
575
+		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function() use ($log) {
576 576
 			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
577 577
 		});
578
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
579
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
578
+		$this->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($log) {
579
+			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <'.$app.'> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
580 580
 		});
581
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
581
+		$this->listen('\OC\Updater', 'appUpgradeCheck', function() use ($log) {
582 582
 			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
583 583
 		});
584
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
585
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
584
+		$this->listen('\OC\Updater', 'appUpgradeStarted', function($app) use ($log) {
585
+			$log->info('\OC\Updater::appUpgradeStarted: Updating <'.$app.'> ...', ['app' => 'updater']);
586 586
 		});
587
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
588
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
587
+		$this->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($log) {
588
+			$log->info('\OC\Updater::appUpgrade: Updated <'.$app.'> to '.$version, ['app' => 'updater']);
589 589
 		});
590
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
591
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
590
+		$this->listen('\OC\Updater', 'failure', function($message) use($log) {
591
+			$log->error('\OC\Updater::failure: '.$message, ['app' => 'updater']);
592 592
 		});
593
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
593
+		$this->listen('\OC\Updater', 'setDebugLogLevel', function() use($log) {
594 594
 			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
595 595
 		});
596
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
597
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
596
+		$this->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use($log) {
597
+			$log->info('\OC\Updater::resetLogLevel: Reset log level to '.$logLevelName.'('.$logLevel.')', ['app' => 'updater']);
598 598
 		});
599
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
599
+		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use($log) {
600 600
 			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
601 601
 		});
602
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
602
+		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use($log) {
603 603
 			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
604 604
 		});
605 605
 
Please login to merge, or discard this patch.
lib/private/legacy/app.php 2 patches
Indentation   +1056 added lines, -1056 removed lines patch added patch discarded remove patch
@@ -62,1060 +62,1060 @@
 block discarded – undo
62 62
  * upgrading and removing apps.
63 63
  */
64 64
 class OC_App {
65
-	static private $adminForms = array();
66
-	static private $personalForms = array();
67
-	static private $appTypes = array();
68
-	static private $loadedApps = array();
69
-	static private $altLogin = array();
70
-	static private $alreadyRegistered = [];
71
-	const officialApp = 200;
72
-
73
-	/**
74
-	 * clean the appId
75
-	 *
76
-	 * @param string|boolean $app AppId that needs to be cleaned
77
-	 * @return string
78
-	 */
79
-	public static function cleanAppId($app) {
80
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
-	}
82
-
83
-	/**
84
-	 * Check if an app is loaded
85
-	 *
86
-	 * @param string $app
87
-	 * @return bool
88
-	 */
89
-	public static function isAppLoaded($app) {
90
-		return in_array($app, self::$loadedApps, true);
91
-	}
92
-
93
-	/**
94
-	 * loads all apps
95
-	 *
96
-	 * @param string[] | string | null $types
97
-	 * @return bool
98
-	 *
99
-	 * This function walks through the ownCloud directory and loads all apps
100
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
101
-	 * exists.
102
-	 *
103
-	 * if $types is set, only apps of those types will be loaded
104
-	 */
105
-	public static function loadApps($types = null) {
106
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
-			return false;
108
-		}
109
-		// Load the enabled apps here
110
-		$apps = self::getEnabledApps();
111
-
112
-		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
114
-			$path = self::getAppPath($app);
115
-			if($path !== false) {
116
-				self::registerAutoloading($app, $path);
117
-			}
118
-		}
119
-
120
-		// prevent app.php from printing output
121
-		ob_start();
122
-		foreach ($apps as $app) {
123
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
-				self::loadApp($app);
125
-			}
126
-		}
127
-		ob_end_clean();
128
-
129
-		return true;
130
-	}
131
-
132
-	/**
133
-	 * load a single app
134
-	 *
135
-	 * @param string $app
136
-	 */
137
-	public static function loadApp($app) {
138
-		self::$loadedApps[] = $app;
139
-		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
141
-			return;
142
-		}
143
-
144
-		// in case someone calls loadApp() directly
145
-		self::registerAutoloading($app, $appPath);
146
-
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
-			self::requireAppFile($app);
150
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
151
-		}
152
-
153
-		$info = self::getAppInfo($app);
154
-		if (!empty($info['activity']['filters'])) {
155
-			foreach ($info['activity']['filters'] as $filter) {
156
-				\OC::$server->getActivityManager()->registerFilter($filter);
157
-			}
158
-		}
159
-		if (!empty($info['activity']['settings'])) {
160
-			foreach ($info['activity']['settings'] as $setting) {
161
-				\OC::$server->getActivityManager()->registerSetting($setting);
162
-			}
163
-		}
164
-		if (!empty($info['activity']['providers'])) {
165
-			foreach ($info['activity']['providers'] as $provider) {
166
-				\OC::$server->getActivityManager()->registerProvider($provider);
167
-			}
168
-		}
169
-
170
-		if (!empty($info['settings']['admin'])) {
171
-			foreach ($info['settings']['admin'] as $setting) {
172
-				\OC::$server->getSettingsManager()->registerSetting('admin', $setting);
173
-			}
174
-		}
175
-		if (!empty($info['settings']['admin-section'])) {
176
-			foreach ($info['settings']['admin-section'] as $section) {
177
-				\OC::$server->getSettingsManager()->registerSection('admin', $section);
178
-			}
179
-		}
180
-		if (!empty($info['settings']['personal'])) {
181
-			foreach ($info['settings']['personal'] as $setting) {
182
-				\OC::$server->getSettingsManager()->registerSetting('personal', $setting);
183
-			}
184
-		}
185
-		if (!empty($info['settings']['personal-section'])) {
186
-			foreach ($info['settings']['personal-section'] as $section) {
187
-				\OC::$server->getSettingsManager()->registerSection('personal', $section);
188
-			}
189
-		}
190
-
191
-		if (!empty($info['collaboration']['plugins'])) {
192
-			// deal with one or many plugin entries
193
-			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
194
-				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
195
-			foreach ($plugins as $plugin) {
196
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
197
-					$pluginInfo = [
198
-						'shareType' => $plugin['@attributes']['share-type'],
199
-						'class' => $plugin['@value'],
200
-					];
201
-					\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
202
-				} else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
203
-					\OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
204
-				}
205
-			}
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * @internal
211
-	 * @param string $app
212
-	 * @param string $path
213
-	 */
214
-	public static function registerAutoloading($app, $path) {
215
-		$key = $app . '-' . $path;
216
-		if(isset(self::$alreadyRegistered[$key])) {
217
-			return;
218
-		}
219
-
220
-		self::$alreadyRegistered[$key] = true;
221
-
222
-		// Register on PSR-4 composer autoloader
223
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
224
-		\OC::$server->registerNamespace($app, $appNamespace);
225
-
226
-		if (file_exists($path . '/composer/autoload.php')) {
227
-			require_once $path . '/composer/autoload.php';
228
-		} else {
229
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
230
-			// Register on legacy autoloader
231
-			\OC::$loader->addValidRoot($path);
232
-		}
233
-
234
-		// Register Test namespace only when testing
235
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
236
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
237
-		}
238
-	}
239
-
240
-	/**
241
-	 * Load app.php from the given app
242
-	 *
243
-	 * @param string $app app name
244
-	 */
245
-	private static function requireAppFile($app) {
246
-		try {
247
-			// encapsulated here to avoid variable scope conflicts
248
-			require_once $app . '/appinfo/app.php';
249
-		} catch (Error $ex) {
250
-			\OC::$server->getLogger()->logException($ex);
251
-			if (!\OC::$server->getAppManager()->isShipped($app)) {
252
-				// Only disable apps which are not shipped
253
-				\OC::$server->getAppManager()->disableApp($app);
254
-			}
255
-		}
256
-	}
257
-
258
-	/**
259
-	 * check if an app is of a specific type
260
-	 *
261
-	 * @param string $app
262
-	 * @param string|array $types
263
-	 * @return bool
264
-	 */
265
-	public static function isType($app, $types) {
266
-		if (is_string($types)) {
267
-			$types = array($types);
268
-		}
269
-		$appTypes = self::getAppTypes($app);
270
-		foreach ($types as $type) {
271
-			if (array_search($type, $appTypes) !== false) {
272
-				return true;
273
-			}
274
-		}
275
-		return false;
276
-	}
277
-
278
-	/**
279
-	 * get the types of an app
280
-	 *
281
-	 * @param string $app
282
-	 * @return array
283
-	 */
284
-	private static function getAppTypes($app) {
285
-		//load the cache
286
-		if (count(self::$appTypes) == 0) {
287
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
288
-		}
289
-
290
-		if (isset(self::$appTypes[$app])) {
291
-			return explode(',', self::$appTypes[$app]);
292
-		} else {
293
-			return array();
294
-		}
295
-	}
296
-
297
-	/**
298
-	 * read app types from info.xml and cache them in the database
299
-	 */
300
-	public static function setAppTypes($app) {
301
-		$appData = self::getAppInfo($app);
302
-		if(!is_array($appData)) {
303
-			return;
304
-		}
305
-
306
-		if (isset($appData['types'])) {
307
-			$appTypes = implode(',', $appData['types']);
308
-		} else {
309
-			$appTypes = '';
310
-			$appData['types'] = [];
311
-		}
312
-
313
-		\OC::$server->getConfig()->setAppValue($app, 'types', $appTypes);
314
-
315
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
316
-			$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'yes');
317
-			if ($enabled !== 'yes' && $enabled !== 'no') {
318
-				\OC::$server->getConfig()->setAppValue($app, 'enabled', 'yes');
319
-			}
320
-		}
321
-	}
322
-
323
-	/**
324
-	 * Returns apps enabled for the current user.
325
-	 *
326
-	 * @param bool $forceRefresh whether to refresh the cache
327
-	 * @param bool $all whether to return apps for all users, not only the
328
-	 * currently logged in one
329
-	 * @return string[]
330
-	 */
331
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
332
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
333
-			return array();
334
-		}
335
-		// in incognito mode or when logged out, $user will be false,
336
-		// which is also the case during an upgrade
337
-		$appManager = \OC::$server->getAppManager();
338
-		if ($all) {
339
-			$user = null;
340
-		} else {
341
-			$user = \OC::$server->getUserSession()->getUser();
342
-		}
343
-
344
-		if (is_null($user)) {
345
-			$apps = $appManager->getInstalledApps();
346
-		} else {
347
-			$apps = $appManager->getEnabledAppsForUser($user);
348
-		}
349
-		$apps = array_filter($apps, function ($app) {
350
-			return $app !== 'files';//we add this manually
351
-		});
352
-		sort($apps);
353
-		array_unshift($apps, 'files');
354
-		return $apps;
355
-	}
356
-
357
-	/**
358
-	 * checks whether or not an app is enabled
359
-	 *
360
-	 * @param string $app app
361
-	 * @return bool
362
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
363
-	 *
364
-	 * This function checks whether or not an app is enabled.
365
-	 */
366
-	public static function isEnabled($app) {
367
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
368
-	}
369
-
370
-	/**
371
-	 * enables an app
372
-	 *
373
-	 * @param string $appId
374
-	 * @param array $groups (optional) when set, only these groups will have access to the app
375
-	 * @throws \Exception
376
-	 * @return void
377
-	 *
378
-	 * This function set an app as enabled in appconfig.
379
-	 */
380
-	public function enable($appId,
381
-						   $groups = null) {
382
-
383
-		// Check if app is already downloaded
384
-		$installer = \OC::$server->query(Installer::class);
385
-		$isDownloaded = $installer->isDownloaded($appId);
386
-
387
-		if(!$isDownloaded) {
388
-			$installer->downloadApp($appId);
389
-		}
390
-
391
-		$installer->installApp($appId);
392
-
393
-		$appManager = \OC::$server->getAppManager();
394
-		if (!is_null($groups)) {
395
-			$groupManager = \OC::$server->getGroupManager();
396
-			$groupsList = [];
397
-			foreach ($groups as $group) {
398
-				$groupItem = $groupManager->get($group);
399
-				if ($groupItem instanceof \OCP\IGroup) {
400
-					$groupsList[] = $groupManager->get($group);
401
-				}
402
-			}
403
-			$appManager->enableAppForGroups($appId, $groupsList);
404
-		} else {
405
-			$appManager->enableApp($appId);
406
-		}
407
-	}
408
-
409
-	// This is private as well. It simply works, so don't ask for more details
410
-	private static function proceedNavigation($list) {
411
-		usort($list, function($a, $b) {
412
-			if (isset($a['order']) && isset($b['order'])) {
413
-				return ($a['order'] < $b['order']) ? -1 : 1;
414
-			} else if (isset($a['order']) || isset($b['order'])) {
415
-				return isset($a['order']) ? -1 : 1;
416
-			} else {
417
-				return ($a['name'] < $b['name']) ? -1 : 1;
418
-			}
419
-		});
420
-
421
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
422
-		foreach ($list as $index => &$navEntry) {
423
-			if ($navEntry['id'] == $activeApp) {
424
-				$navEntry['active'] = true;
425
-			} else {
426
-				$navEntry['active'] = false;
427
-			}
428
-		}
429
-		unset($navEntry);
430
-
431
-		return $list;
432
-	}
433
-
434
-	/**
435
-	 * Get the path where to install apps
436
-	 *
437
-	 * @return string|false
438
-	 */
439
-	public static function getInstallPath() {
440
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
441
-			return false;
442
-		}
443
-
444
-		foreach (OC::$APPSROOTS as $dir) {
445
-			if (isset($dir['writable']) && $dir['writable'] === true) {
446
-				return $dir['path'];
447
-			}
448
-		}
449
-
450
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
451
-		return null;
452
-	}
453
-
454
-
455
-	/**
456
-	 * search for an app in all app-directories
457
-	 *
458
-	 * @param string $appId
459
-	 * @return false|string
460
-	 */
461
-	public static function findAppInDirectories($appId) {
462
-		$sanitizedAppId = self::cleanAppId($appId);
463
-		if($sanitizedAppId !== $appId) {
464
-			return false;
465
-		}
466
-		static $app_dir = array();
467
-
468
-		if (isset($app_dir[$appId])) {
469
-			return $app_dir[$appId];
470
-		}
471
-
472
-		$possibleApps = array();
473
-		foreach (OC::$APPSROOTS as $dir) {
474
-			if (file_exists($dir['path'] . '/' . $appId)) {
475
-				$possibleApps[] = $dir;
476
-			}
477
-		}
478
-
479
-		if (empty($possibleApps)) {
480
-			return false;
481
-		} elseif (count($possibleApps) === 1) {
482
-			$dir = array_shift($possibleApps);
483
-			$app_dir[$appId] = $dir;
484
-			return $dir;
485
-		} else {
486
-			$versionToLoad = array();
487
-			foreach ($possibleApps as $possibleApp) {
488
-				$version = self::getAppVersionByPath($possibleApp['path']);
489
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
490
-					$versionToLoad = array(
491
-						'dir' => $possibleApp,
492
-						'version' => $version,
493
-					);
494
-				}
495
-			}
496
-			$app_dir[$appId] = $versionToLoad['dir'];
497
-			return $versionToLoad['dir'];
498
-			//TODO - write test
499
-		}
500
-	}
501
-
502
-	/**
503
-	 * Get the directory for the given app.
504
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
505
-	 *
506
-	 * @param string $appId
507
-	 * @return string|false
508
-	 */
509
-	public static function getAppPath($appId) {
510
-		if ($appId === null || trim($appId) === '') {
511
-			return false;
512
-		}
513
-
514
-		if (($dir = self::findAppInDirectories($appId)) != false) {
515
-			return $dir['path'] . '/' . $appId;
516
-		}
517
-		return false;
518
-	}
519
-
520
-	/**
521
-	 * Get the path for the given app on the access
522
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
523
-	 *
524
-	 * @param string $appId
525
-	 * @return string|false
526
-	 */
527
-	public static function getAppWebPath($appId) {
528
-		if (($dir = self::findAppInDirectories($appId)) != false) {
529
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
530
-		}
531
-		return false;
532
-	}
533
-
534
-	/**
535
-	 * get the last version of the app from appinfo/info.xml
536
-	 *
537
-	 * @param string $appId
538
-	 * @param bool $useCache
539
-	 * @return string
540
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
541
-	 */
542
-	public static function getAppVersion($appId, $useCache = true) {
543
-		return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
544
-	}
545
-
546
-	/**
547
-	 * get app's version based on it's path
548
-	 *
549
-	 * @param string $path
550
-	 * @return string
551
-	 */
552
-	public static function getAppVersionByPath($path) {
553
-		$infoFile = $path . '/appinfo/info.xml';
554
-		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
555
-		return isset($appData['version']) ? $appData['version'] : '';
556
-	}
557
-
558
-
559
-	/**
560
-	 * Read all app metadata from the info.xml file
561
-	 *
562
-	 * @param string $appId id of the app or the path of the info.xml file
563
-	 * @param bool $path
564
-	 * @param string $lang
565
-	 * @return array|null
566
-	 * @note all data is read from info.xml, not just pre-defined fields
567
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
568
-	 */
569
-	public static function getAppInfo($appId, $path = false, $lang = null) {
570
-		return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
571
-	}
572
-
573
-	/**
574
-	 * Returns the navigation
575
-	 *
576
-	 * @return array
577
-	 *
578
-	 * This function returns an array containing all entries added. The
579
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
580
-	 * given for each app the following keys exist:
581
-	 *   - active: boolean, signals if the user is on this navigation entry
582
-	 */
583
-	public static function getNavigation() {
584
-		$entries = OC::$server->getNavigationManager()->getAll();
585
-		return self::proceedNavigation($entries);
586
-	}
587
-
588
-	/**
589
-	 * Returns the Settings Navigation
590
-	 *
591
-	 * @return string[]
592
-	 *
593
-	 * This function returns an array containing all settings pages added. The
594
-	 * entries are sorted by the key 'order' ascending.
595
-	 */
596
-	public static function getSettingsNavigation() {
597
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
598
-		return self::proceedNavigation($entries);
599
-	}
600
-
601
-	/**
602
-	 * get the id of loaded app
603
-	 *
604
-	 * @return string
605
-	 */
606
-	public static function getCurrentApp() {
607
-		$request = \OC::$server->getRequest();
608
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
609
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
610
-		if (empty($topFolder)) {
611
-			$path_info = $request->getPathInfo();
612
-			if ($path_info) {
613
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
614
-			}
615
-		}
616
-		if ($topFolder == 'apps') {
617
-			$length = strlen($topFolder);
618
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
619
-		} else {
620
-			return $topFolder;
621
-		}
622
-	}
623
-
624
-	/**
625
-	 * @param string $type
626
-	 * @return array
627
-	 */
628
-	public static function getForms($type) {
629
-		$forms = array();
630
-		switch ($type) {
631
-			case 'admin':
632
-				$source = self::$adminForms;
633
-				break;
634
-			case 'personal':
635
-				$source = self::$personalForms;
636
-				break;
637
-			default:
638
-				return array();
639
-		}
640
-		foreach ($source as $form) {
641
-			$forms[] = include $form;
642
-		}
643
-		return $forms;
644
-	}
645
-
646
-	/**
647
-	 * register an admin form to be shown
648
-	 *
649
-	 * @param string $app
650
-	 * @param string $page
651
-	 */
652
-	public static function registerAdmin($app, $page) {
653
-		self::$adminForms[] = $app . '/' . $page . '.php';
654
-	}
655
-
656
-	/**
657
-	 * register a personal form to be shown
658
-	 * @param string $app
659
-	 * @param string $page
660
-	 */
661
-	public static function registerPersonal($app, $page) {
662
-		self::$personalForms[] = $app . '/' . $page . '.php';
663
-	}
664
-
665
-	/**
666
-	 * @param array $entry
667
-	 */
668
-	public static function registerLogIn(array $entry) {
669
-		self::$altLogin[] = $entry;
670
-	}
671
-
672
-	/**
673
-	 * @return array
674
-	 */
675
-	public static function getAlternativeLogIns() {
676
-		return self::$altLogin;
677
-	}
678
-
679
-	/**
680
-	 * get a list of all apps in the apps folder
681
-	 *
682
-	 * @return array an array of app names (string IDs)
683
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
684
-	 */
685
-	public static function getAllApps() {
686
-
687
-		$apps = array();
688
-
689
-		foreach (OC::$APPSROOTS as $apps_dir) {
690
-			if (!is_readable($apps_dir['path'])) {
691
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
692
-				continue;
693
-			}
694
-			$dh = opendir($apps_dir['path']);
695
-
696
-			if (is_resource($dh)) {
697
-				while (($file = readdir($dh)) !== false) {
698
-
699
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
700
-
701
-						$apps[] = $file;
702
-					}
703
-				}
704
-			}
705
-		}
706
-
707
-		$apps = array_unique($apps);
708
-
709
-		return $apps;
710
-	}
711
-
712
-	/**
713
-	 * List all apps, this is used in apps.php
714
-	 *
715
-	 * @return array
716
-	 */
717
-	public function listAllApps() {
718
-		$installedApps = OC_App::getAllApps();
719
-
720
-		$appManager = \OC::$server->getAppManager();
721
-		//we don't want to show configuration for these
722
-		$blacklist = $appManager->getAlwaysEnabledApps();
723
-		$appList = array();
724
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
725
-		$urlGenerator = \OC::$server->getURLGenerator();
726
-
727
-		foreach ($installedApps as $app) {
728
-			if (array_search($app, $blacklist) === false) {
729
-
730
-				$info = OC_App::getAppInfo($app, false, $langCode);
731
-				if (!is_array($info)) {
732
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
733
-					continue;
734
-				}
735
-
736
-				if (!isset($info['name'])) {
737
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
738
-					continue;
739
-				}
740
-
741
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
742
-				$info['groups'] = null;
743
-				if ($enabled === 'yes') {
744
-					$active = true;
745
-				} else if ($enabled === 'no') {
746
-					$active = false;
747
-				} else {
748
-					$active = true;
749
-					$info['groups'] = $enabled;
750
-				}
751
-
752
-				$info['active'] = $active;
753
-
754
-				if ($appManager->isShipped($app)) {
755
-					$info['internal'] = true;
756
-					$info['level'] = self::officialApp;
757
-					$info['removable'] = false;
758
-				} else {
759
-					$info['internal'] = false;
760
-					$info['removable'] = true;
761
-				}
762
-
763
-				$appPath = self::getAppPath($app);
764
-				if($appPath !== false) {
765
-					$appIcon = $appPath . '/img/' . $app . '.svg';
766
-					if (file_exists($appIcon)) {
767
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
768
-						$info['previewAsIcon'] = true;
769
-					} else {
770
-						$appIcon = $appPath . '/img/app.svg';
771
-						if (file_exists($appIcon)) {
772
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
773
-							$info['previewAsIcon'] = true;
774
-						}
775
-					}
776
-				}
777
-				// fix documentation
778
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
779
-					foreach ($info['documentation'] as $key => $url) {
780
-						// If it is not an absolute URL we assume it is a key
781
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
782
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
783
-							$url = $urlGenerator->linkToDocs($url);
784
-						}
785
-
786
-						$info['documentation'][$key] = $url;
787
-					}
788
-				}
789
-
790
-				$info['version'] = OC_App::getAppVersion($app);
791
-				$appList[] = $info;
792
-			}
793
-		}
794
-
795
-		return $appList;
796
-	}
797
-
798
-	public static function shouldUpgrade($app) {
799
-		$versions = self::getAppVersions();
800
-		$currentVersion = OC_App::getAppVersion($app);
801
-		if ($currentVersion && isset($versions[$app])) {
802
-			$installedVersion = $versions[$app];
803
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
804
-				return true;
805
-			}
806
-		}
807
-		return false;
808
-	}
809
-
810
-	/**
811
-	 * Adjust the number of version parts of $version1 to match
812
-	 * the number of version parts of $version2.
813
-	 *
814
-	 * @param string $version1 version to adjust
815
-	 * @param string $version2 version to take the number of parts from
816
-	 * @return string shortened $version1
817
-	 */
818
-	private static function adjustVersionParts($version1, $version2) {
819
-		$version1 = explode('.', $version1);
820
-		$version2 = explode('.', $version2);
821
-		// reduce $version1 to match the number of parts in $version2
822
-		while (count($version1) > count($version2)) {
823
-			array_pop($version1);
824
-		}
825
-		// if $version1 does not have enough parts, add some
826
-		while (count($version1) < count($version2)) {
827
-			$version1[] = '0';
828
-		}
829
-		return implode('.', $version1);
830
-	}
831
-
832
-	/**
833
-	 * Check whether the current ownCloud version matches the given
834
-	 * application's version requirements.
835
-	 *
836
-	 * The comparison is made based on the number of parts that the
837
-	 * app info version has. For example for ownCloud 6.0.3 if the
838
-	 * app info version is expecting version 6.0, the comparison is
839
-	 * made on the first two parts of the ownCloud version.
840
-	 * This means that it's possible to specify "requiremin" => 6
841
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
842
-	 *
843
-	 * @param string $ocVersion ownCloud version to check against
844
-	 * @param array $appInfo app info (from xml)
845
-	 *
846
-	 * @return boolean true if compatible, otherwise false
847
-	 */
848
-	public static function isAppCompatible($ocVersion, $appInfo) {
849
-		$requireMin = '';
850
-		$requireMax = '';
851
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
852
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
853
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
854
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
855
-		} else if (isset($appInfo['requiremin'])) {
856
-			$requireMin = $appInfo['requiremin'];
857
-		} else if (isset($appInfo['require'])) {
858
-			$requireMin = $appInfo['require'];
859
-		}
860
-
861
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
862
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
863
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
864
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
865
-		} else if (isset($appInfo['requiremax'])) {
866
-			$requireMax = $appInfo['requiremax'];
867
-		}
868
-
869
-		if (is_array($ocVersion)) {
870
-			$ocVersion = implode('.', $ocVersion);
871
-		}
872
-
873
-		if (!empty($requireMin)
874
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
875
-		) {
876
-
877
-			return false;
878
-		}
879
-
880
-		if (!empty($requireMax)
881
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
882
-		) {
883
-			return false;
884
-		}
885
-
886
-		return true;
887
-	}
888
-
889
-	/**
890
-	 * get the installed version of all apps
891
-	 */
892
-	public static function getAppVersions() {
893
-		static $versions;
894
-
895
-		if(!$versions) {
896
-			$appConfig = \OC::$server->getAppConfig();
897
-			$versions = $appConfig->getValues(false, 'installed_version');
898
-		}
899
-		return $versions;
900
-	}
901
-
902
-	/**
903
-	 * update the database for the app and call the update script
904
-	 *
905
-	 * @param string $appId
906
-	 * @return bool
907
-	 */
908
-	public static function updateApp($appId) {
909
-		$appPath = self::getAppPath($appId);
910
-		if($appPath === false) {
911
-			return false;
912
-		}
913
-		self::registerAutoloading($appId, $appPath);
914
-
915
-		$appData = self::getAppInfo($appId);
916
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
917
-
918
-		if (file_exists($appPath . '/appinfo/database.xml')) {
919
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
920
-		} else {
921
-			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
922
-			$ms->migrate();
923
-		}
924
-
925
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
926
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
927
-		// update appversion in app manager
928
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
929
-
930
-		// run upgrade code
931
-		if (file_exists($appPath . '/appinfo/update.php')) {
932
-			self::loadApp($appId);
933
-			include $appPath . '/appinfo/update.php';
934
-		}
935
-		self::setupBackgroundJobs($appData['background-jobs']);
936
-
937
-		//set remote/public handlers
938
-		if (array_key_exists('ocsid', $appData)) {
939
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
940
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
941
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
942
-		}
943
-		foreach ($appData['remote'] as $name => $path) {
944
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
945
-		}
946
-		foreach ($appData['public'] as $name => $path) {
947
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
948
-		}
949
-
950
-		self::setAppTypes($appId);
951
-
952
-		$version = \OC_App::getAppVersion($appId);
953
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
954
-
955
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
956
-			ManagerEvent::EVENT_APP_UPDATE, $appId
957
-		));
958
-
959
-		return true;
960
-	}
961
-
962
-	/**
963
-	 * @param string $appId
964
-	 * @param string[] $steps
965
-	 * @throws \OC\NeedsUpdateException
966
-	 */
967
-	public static function executeRepairSteps($appId, array $steps) {
968
-		if (empty($steps)) {
969
-			return;
970
-		}
971
-		// load the app
972
-		self::loadApp($appId);
973
-
974
-		$dispatcher = OC::$server->getEventDispatcher();
975
-
976
-		// load the steps
977
-		$r = new Repair([], $dispatcher);
978
-		foreach ($steps as $step) {
979
-			try {
980
-				$r->addStep($step);
981
-			} catch (Exception $ex) {
982
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
983
-				\OC::$server->getLogger()->logException($ex);
984
-			}
985
-		}
986
-		// run the steps
987
-		$r->run();
988
-	}
989
-
990
-	public static function setupBackgroundJobs(array $jobs) {
991
-		$queue = \OC::$server->getJobList();
992
-		foreach ($jobs as $job) {
993
-			$queue->add($job);
994
-		}
995
-	}
996
-
997
-	/**
998
-	 * @param string $appId
999
-	 * @param string[] $steps
1000
-	 */
1001
-	private static function setupLiveMigrations($appId, array $steps) {
1002
-		$queue = \OC::$server->getJobList();
1003
-		foreach ($steps as $step) {
1004
-			$queue->add('OC\Migration\BackgroundRepair', [
1005
-				'app' => $appId,
1006
-				'step' => $step]);
1007
-		}
1008
-	}
1009
-
1010
-	/**
1011
-	 * @param string $appId
1012
-	 * @return \OC\Files\View|false
1013
-	 */
1014
-	public static function getStorage($appId) {
1015
-		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1016
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1017
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1018
-				if (!$view->file_exists($appId)) {
1019
-					$view->mkdir($appId);
1020
-				}
1021
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1022
-			} else {
1023
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1024
-				return false;
1025
-			}
1026
-		} else {
1027
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1028
-			return false;
1029
-		}
1030
-	}
1031
-
1032
-	protected static function findBestL10NOption($options, $lang) {
1033
-		$fallback = $similarLangFallback = $englishFallback = false;
1034
-
1035
-		$lang = strtolower($lang);
1036
-		$similarLang = $lang;
1037
-		if (strpos($similarLang, '_')) {
1038
-			// For "de_DE" we want to find "de" and the other way around
1039
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1040
-		}
1041
-
1042
-		foreach ($options as $option) {
1043
-			if (is_array($option)) {
1044
-				if ($fallback === false) {
1045
-					$fallback = $option['@value'];
1046
-				}
1047
-
1048
-				if (!isset($option['@attributes']['lang'])) {
1049
-					continue;
1050
-				}
1051
-
1052
-				$attributeLang = strtolower($option['@attributes']['lang']);
1053
-				if ($attributeLang === $lang) {
1054
-					return $option['@value'];
1055
-				}
1056
-
1057
-				if ($attributeLang === $similarLang) {
1058
-					$similarLangFallback = $option['@value'];
1059
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1060
-					if ($similarLangFallback === false) {
1061
-						$similarLangFallback =  $option['@value'];
1062
-					}
1063
-				}
1064
-			} else {
1065
-				$englishFallback = $option;
1066
-			}
1067
-		}
1068
-
1069
-		if ($similarLangFallback !== false) {
1070
-			return $similarLangFallback;
1071
-		} else if ($englishFallback !== false) {
1072
-			return $englishFallback;
1073
-		}
1074
-		return (string) $fallback;
1075
-	}
1076
-
1077
-	/**
1078
-	 * parses the app data array and enhanced the 'description' value
1079
-	 *
1080
-	 * @param array $data the app data
1081
-	 * @param string $lang
1082
-	 * @return array improved app data
1083
-	 */
1084
-	public static function parseAppInfo(array $data, $lang = null) {
1085
-
1086
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1087
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1088
-		}
1089
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1090
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1091
-		}
1092
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1093
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1094
-		} else if (isset($data['description']) && is_string($data['description'])) {
1095
-			$data['description'] = trim($data['description']);
1096
-		} else  {
1097
-			$data['description'] = '';
1098
-		}
1099
-
1100
-		return $data;
1101
-	}
1102
-
1103
-	/**
1104
-	 * @param \OCP\IConfig $config
1105
-	 * @param \OCP\IL10N $l
1106
-	 * @param array $info
1107
-	 * @throws \Exception
1108
-	 */
1109
-	public static function checkAppDependencies($config, $l, $info) {
1110
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1111
-		$missing = $dependencyAnalyzer->analyze($info);
1112
-		if (!empty($missing)) {
1113
-			$missingMsg = implode(PHP_EOL, $missing);
1114
-			throw new \Exception(
1115
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1116
-					[$info['name'], $missingMsg]
1117
-				)
1118
-			);
1119
-		}
1120
-	}
65
+    static private $adminForms = array();
66
+    static private $personalForms = array();
67
+    static private $appTypes = array();
68
+    static private $loadedApps = array();
69
+    static private $altLogin = array();
70
+    static private $alreadyRegistered = [];
71
+    const officialApp = 200;
72
+
73
+    /**
74
+     * clean the appId
75
+     *
76
+     * @param string|boolean $app AppId that needs to be cleaned
77
+     * @return string
78
+     */
79
+    public static function cleanAppId($app) {
80
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
+    }
82
+
83
+    /**
84
+     * Check if an app is loaded
85
+     *
86
+     * @param string $app
87
+     * @return bool
88
+     */
89
+    public static function isAppLoaded($app) {
90
+        return in_array($app, self::$loadedApps, true);
91
+    }
92
+
93
+    /**
94
+     * loads all apps
95
+     *
96
+     * @param string[] | string | null $types
97
+     * @return bool
98
+     *
99
+     * This function walks through the ownCloud directory and loads all apps
100
+     * it can find. A directory contains an app if the file /appinfo/info.xml
101
+     * exists.
102
+     *
103
+     * if $types is set, only apps of those types will be loaded
104
+     */
105
+    public static function loadApps($types = null) {
106
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
+            return false;
108
+        }
109
+        // Load the enabled apps here
110
+        $apps = self::getEnabledApps();
111
+
112
+        // Add each apps' folder as allowed class path
113
+        foreach($apps as $app) {
114
+            $path = self::getAppPath($app);
115
+            if($path !== false) {
116
+                self::registerAutoloading($app, $path);
117
+            }
118
+        }
119
+
120
+        // prevent app.php from printing output
121
+        ob_start();
122
+        foreach ($apps as $app) {
123
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
+                self::loadApp($app);
125
+            }
126
+        }
127
+        ob_end_clean();
128
+
129
+        return true;
130
+    }
131
+
132
+    /**
133
+     * load a single app
134
+     *
135
+     * @param string $app
136
+     */
137
+    public static function loadApp($app) {
138
+        self::$loadedApps[] = $app;
139
+        $appPath = self::getAppPath($app);
140
+        if($appPath === false) {
141
+            return;
142
+        }
143
+
144
+        // in case someone calls loadApp() directly
145
+        self::registerAutoloading($app, $appPath);
146
+
147
+        if (is_file($appPath . '/appinfo/app.php')) {
148
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
+            self::requireAppFile($app);
150
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
151
+        }
152
+
153
+        $info = self::getAppInfo($app);
154
+        if (!empty($info['activity']['filters'])) {
155
+            foreach ($info['activity']['filters'] as $filter) {
156
+                \OC::$server->getActivityManager()->registerFilter($filter);
157
+            }
158
+        }
159
+        if (!empty($info['activity']['settings'])) {
160
+            foreach ($info['activity']['settings'] as $setting) {
161
+                \OC::$server->getActivityManager()->registerSetting($setting);
162
+            }
163
+        }
164
+        if (!empty($info['activity']['providers'])) {
165
+            foreach ($info['activity']['providers'] as $provider) {
166
+                \OC::$server->getActivityManager()->registerProvider($provider);
167
+            }
168
+        }
169
+
170
+        if (!empty($info['settings']['admin'])) {
171
+            foreach ($info['settings']['admin'] as $setting) {
172
+                \OC::$server->getSettingsManager()->registerSetting('admin', $setting);
173
+            }
174
+        }
175
+        if (!empty($info['settings']['admin-section'])) {
176
+            foreach ($info['settings']['admin-section'] as $section) {
177
+                \OC::$server->getSettingsManager()->registerSection('admin', $section);
178
+            }
179
+        }
180
+        if (!empty($info['settings']['personal'])) {
181
+            foreach ($info['settings']['personal'] as $setting) {
182
+                \OC::$server->getSettingsManager()->registerSetting('personal', $setting);
183
+            }
184
+        }
185
+        if (!empty($info['settings']['personal-section'])) {
186
+            foreach ($info['settings']['personal-section'] as $section) {
187
+                \OC::$server->getSettingsManager()->registerSection('personal', $section);
188
+            }
189
+        }
190
+
191
+        if (!empty($info['collaboration']['plugins'])) {
192
+            // deal with one or many plugin entries
193
+            $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
194
+                [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
195
+            foreach ($plugins as $plugin) {
196
+                if($plugin['@attributes']['type'] === 'collaborator-search') {
197
+                    $pluginInfo = [
198
+                        'shareType' => $plugin['@attributes']['share-type'],
199
+                        'class' => $plugin['@value'],
200
+                    ];
201
+                    \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
202
+                } else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
203
+                    \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
204
+                }
205
+            }
206
+        }
207
+    }
208
+
209
+    /**
210
+     * @internal
211
+     * @param string $app
212
+     * @param string $path
213
+     */
214
+    public static function registerAutoloading($app, $path) {
215
+        $key = $app . '-' . $path;
216
+        if(isset(self::$alreadyRegistered[$key])) {
217
+            return;
218
+        }
219
+
220
+        self::$alreadyRegistered[$key] = true;
221
+
222
+        // Register on PSR-4 composer autoloader
223
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
224
+        \OC::$server->registerNamespace($app, $appNamespace);
225
+
226
+        if (file_exists($path . '/composer/autoload.php')) {
227
+            require_once $path . '/composer/autoload.php';
228
+        } else {
229
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
230
+            // Register on legacy autoloader
231
+            \OC::$loader->addValidRoot($path);
232
+        }
233
+
234
+        // Register Test namespace only when testing
235
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
236
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
237
+        }
238
+    }
239
+
240
+    /**
241
+     * Load app.php from the given app
242
+     *
243
+     * @param string $app app name
244
+     */
245
+    private static function requireAppFile($app) {
246
+        try {
247
+            // encapsulated here to avoid variable scope conflicts
248
+            require_once $app . '/appinfo/app.php';
249
+        } catch (Error $ex) {
250
+            \OC::$server->getLogger()->logException($ex);
251
+            if (!\OC::$server->getAppManager()->isShipped($app)) {
252
+                // Only disable apps which are not shipped
253
+                \OC::$server->getAppManager()->disableApp($app);
254
+            }
255
+        }
256
+    }
257
+
258
+    /**
259
+     * check if an app is of a specific type
260
+     *
261
+     * @param string $app
262
+     * @param string|array $types
263
+     * @return bool
264
+     */
265
+    public static function isType($app, $types) {
266
+        if (is_string($types)) {
267
+            $types = array($types);
268
+        }
269
+        $appTypes = self::getAppTypes($app);
270
+        foreach ($types as $type) {
271
+            if (array_search($type, $appTypes) !== false) {
272
+                return true;
273
+            }
274
+        }
275
+        return false;
276
+    }
277
+
278
+    /**
279
+     * get the types of an app
280
+     *
281
+     * @param string $app
282
+     * @return array
283
+     */
284
+    private static function getAppTypes($app) {
285
+        //load the cache
286
+        if (count(self::$appTypes) == 0) {
287
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
288
+        }
289
+
290
+        if (isset(self::$appTypes[$app])) {
291
+            return explode(',', self::$appTypes[$app]);
292
+        } else {
293
+            return array();
294
+        }
295
+    }
296
+
297
+    /**
298
+     * read app types from info.xml and cache them in the database
299
+     */
300
+    public static function setAppTypes($app) {
301
+        $appData = self::getAppInfo($app);
302
+        if(!is_array($appData)) {
303
+            return;
304
+        }
305
+
306
+        if (isset($appData['types'])) {
307
+            $appTypes = implode(',', $appData['types']);
308
+        } else {
309
+            $appTypes = '';
310
+            $appData['types'] = [];
311
+        }
312
+
313
+        \OC::$server->getConfig()->setAppValue($app, 'types', $appTypes);
314
+
315
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
316
+            $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'yes');
317
+            if ($enabled !== 'yes' && $enabled !== 'no') {
318
+                \OC::$server->getConfig()->setAppValue($app, 'enabled', 'yes');
319
+            }
320
+        }
321
+    }
322
+
323
+    /**
324
+     * Returns apps enabled for the current user.
325
+     *
326
+     * @param bool $forceRefresh whether to refresh the cache
327
+     * @param bool $all whether to return apps for all users, not only the
328
+     * currently logged in one
329
+     * @return string[]
330
+     */
331
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
332
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
333
+            return array();
334
+        }
335
+        // in incognito mode or when logged out, $user will be false,
336
+        // which is also the case during an upgrade
337
+        $appManager = \OC::$server->getAppManager();
338
+        if ($all) {
339
+            $user = null;
340
+        } else {
341
+            $user = \OC::$server->getUserSession()->getUser();
342
+        }
343
+
344
+        if (is_null($user)) {
345
+            $apps = $appManager->getInstalledApps();
346
+        } else {
347
+            $apps = $appManager->getEnabledAppsForUser($user);
348
+        }
349
+        $apps = array_filter($apps, function ($app) {
350
+            return $app !== 'files';//we add this manually
351
+        });
352
+        sort($apps);
353
+        array_unshift($apps, 'files');
354
+        return $apps;
355
+    }
356
+
357
+    /**
358
+     * checks whether or not an app is enabled
359
+     *
360
+     * @param string $app app
361
+     * @return bool
362
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
363
+     *
364
+     * This function checks whether or not an app is enabled.
365
+     */
366
+    public static function isEnabled($app) {
367
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
368
+    }
369
+
370
+    /**
371
+     * enables an app
372
+     *
373
+     * @param string $appId
374
+     * @param array $groups (optional) when set, only these groups will have access to the app
375
+     * @throws \Exception
376
+     * @return void
377
+     *
378
+     * This function set an app as enabled in appconfig.
379
+     */
380
+    public function enable($appId,
381
+                            $groups = null) {
382
+
383
+        // Check if app is already downloaded
384
+        $installer = \OC::$server->query(Installer::class);
385
+        $isDownloaded = $installer->isDownloaded($appId);
386
+
387
+        if(!$isDownloaded) {
388
+            $installer->downloadApp($appId);
389
+        }
390
+
391
+        $installer->installApp($appId);
392
+
393
+        $appManager = \OC::$server->getAppManager();
394
+        if (!is_null($groups)) {
395
+            $groupManager = \OC::$server->getGroupManager();
396
+            $groupsList = [];
397
+            foreach ($groups as $group) {
398
+                $groupItem = $groupManager->get($group);
399
+                if ($groupItem instanceof \OCP\IGroup) {
400
+                    $groupsList[] = $groupManager->get($group);
401
+                }
402
+            }
403
+            $appManager->enableAppForGroups($appId, $groupsList);
404
+        } else {
405
+            $appManager->enableApp($appId);
406
+        }
407
+    }
408
+
409
+    // This is private as well. It simply works, so don't ask for more details
410
+    private static function proceedNavigation($list) {
411
+        usort($list, function($a, $b) {
412
+            if (isset($a['order']) && isset($b['order'])) {
413
+                return ($a['order'] < $b['order']) ? -1 : 1;
414
+            } else if (isset($a['order']) || isset($b['order'])) {
415
+                return isset($a['order']) ? -1 : 1;
416
+            } else {
417
+                return ($a['name'] < $b['name']) ? -1 : 1;
418
+            }
419
+        });
420
+
421
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
422
+        foreach ($list as $index => &$navEntry) {
423
+            if ($navEntry['id'] == $activeApp) {
424
+                $navEntry['active'] = true;
425
+            } else {
426
+                $navEntry['active'] = false;
427
+            }
428
+        }
429
+        unset($navEntry);
430
+
431
+        return $list;
432
+    }
433
+
434
+    /**
435
+     * Get the path where to install apps
436
+     *
437
+     * @return string|false
438
+     */
439
+    public static function getInstallPath() {
440
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
441
+            return false;
442
+        }
443
+
444
+        foreach (OC::$APPSROOTS as $dir) {
445
+            if (isset($dir['writable']) && $dir['writable'] === true) {
446
+                return $dir['path'];
447
+            }
448
+        }
449
+
450
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
451
+        return null;
452
+    }
453
+
454
+
455
+    /**
456
+     * search for an app in all app-directories
457
+     *
458
+     * @param string $appId
459
+     * @return false|string
460
+     */
461
+    public static function findAppInDirectories($appId) {
462
+        $sanitizedAppId = self::cleanAppId($appId);
463
+        if($sanitizedAppId !== $appId) {
464
+            return false;
465
+        }
466
+        static $app_dir = array();
467
+
468
+        if (isset($app_dir[$appId])) {
469
+            return $app_dir[$appId];
470
+        }
471
+
472
+        $possibleApps = array();
473
+        foreach (OC::$APPSROOTS as $dir) {
474
+            if (file_exists($dir['path'] . '/' . $appId)) {
475
+                $possibleApps[] = $dir;
476
+            }
477
+        }
478
+
479
+        if (empty($possibleApps)) {
480
+            return false;
481
+        } elseif (count($possibleApps) === 1) {
482
+            $dir = array_shift($possibleApps);
483
+            $app_dir[$appId] = $dir;
484
+            return $dir;
485
+        } else {
486
+            $versionToLoad = array();
487
+            foreach ($possibleApps as $possibleApp) {
488
+                $version = self::getAppVersionByPath($possibleApp['path']);
489
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
490
+                    $versionToLoad = array(
491
+                        'dir' => $possibleApp,
492
+                        'version' => $version,
493
+                    );
494
+                }
495
+            }
496
+            $app_dir[$appId] = $versionToLoad['dir'];
497
+            return $versionToLoad['dir'];
498
+            //TODO - write test
499
+        }
500
+    }
501
+
502
+    /**
503
+     * Get the directory for the given app.
504
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
505
+     *
506
+     * @param string $appId
507
+     * @return string|false
508
+     */
509
+    public static function getAppPath($appId) {
510
+        if ($appId === null || trim($appId) === '') {
511
+            return false;
512
+        }
513
+
514
+        if (($dir = self::findAppInDirectories($appId)) != false) {
515
+            return $dir['path'] . '/' . $appId;
516
+        }
517
+        return false;
518
+    }
519
+
520
+    /**
521
+     * Get the path for the given app on the access
522
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
523
+     *
524
+     * @param string $appId
525
+     * @return string|false
526
+     */
527
+    public static function getAppWebPath($appId) {
528
+        if (($dir = self::findAppInDirectories($appId)) != false) {
529
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
530
+        }
531
+        return false;
532
+    }
533
+
534
+    /**
535
+     * get the last version of the app from appinfo/info.xml
536
+     *
537
+     * @param string $appId
538
+     * @param bool $useCache
539
+     * @return string
540
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
541
+     */
542
+    public static function getAppVersion($appId, $useCache = true) {
543
+        return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
544
+    }
545
+
546
+    /**
547
+     * get app's version based on it's path
548
+     *
549
+     * @param string $path
550
+     * @return string
551
+     */
552
+    public static function getAppVersionByPath($path) {
553
+        $infoFile = $path . '/appinfo/info.xml';
554
+        $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
555
+        return isset($appData['version']) ? $appData['version'] : '';
556
+    }
557
+
558
+
559
+    /**
560
+     * Read all app metadata from the info.xml file
561
+     *
562
+     * @param string $appId id of the app or the path of the info.xml file
563
+     * @param bool $path
564
+     * @param string $lang
565
+     * @return array|null
566
+     * @note all data is read from info.xml, not just pre-defined fields
567
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
568
+     */
569
+    public static function getAppInfo($appId, $path = false, $lang = null) {
570
+        return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
571
+    }
572
+
573
+    /**
574
+     * Returns the navigation
575
+     *
576
+     * @return array
577
+     *
578
+     * This function returns an array containing all entries added. The
579
+     * entries are sorted by the key 'order' ascending. Additional to the keys
580
+     * given for each app the following keys exist:
581
+     *   - active: boolean, signals if the user is on this navigation entry
582
+     */
583
+    public static function getNavigation() {
584
+        $entries = OC::$server->getNavigationManager()->getAll();
585
+        return self::proceedNavigation($entries);
586
+    }
587
+
588
+    /**
589
+     * Returns the Settings Navigation
590
+     *
591
+     * @return string[]
592
+     *
593
+     * This function returns an array containing all settings pages added. The
594
+     * entries are sorted by the key 'order' ascending.
595
+     */
596
+    public static function getSettingsNavigation() {
597
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
598
+        return self::proceedNavigation($entries);
599
+    }
600
+
601
+    /**
602
+     * get the id of loaded app
603
+     *
604
+     * @return string
605
+     */
606
+    public static function getCurrentApp() {
607
+        $request = \OC::$server->getRequest();
608
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
609
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
610
+        if (empty($topFolder)) {
611
+            $path_info = $request->getPathInfo();
612
+            if ($path_info) {
613
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
614
+            }
615
+        }
616
+        if ($topFolder == 'apps') {
617
+            $length = strlen($topFolder);
618
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
619
+        } else {
620
+            return $topFolder;
621
+        }
622
+    }
623
+
624
+    /**
625
+     * @param string $type
626
+     * @return array
627
+     */
628
+    public static function getForms($type) {
629
+        $forms = array();
630
+        switch ($type) {
631
+            case 'admin':
632
+                $source = self::$adminForms;
633
+                break;
634
+            case 'personal':
635
+                $source = self::$personalForms;
636
+                break;
637
+            default:
638
+                return array();
639
+        }
640
+        foreach ($source as $form) {
641
+            $forms[] = include $form;
642
+        }
643
+        return $forms;
644
+    }
645
+
646
+    /**
647
+     * register an admin form to be shown
648
+     *
649
+     * @param string $app
650
+     * @param string $page
651
+     */
652
+    public static function registerAdmin($app, $page) {
653
+        self::$adminForms[] = $app . '/' . $page . '.php';
654
+    }
655
+
656
+    /**
657
+     * register a personal form to be shown
658
+     * @param string $app
659
+     * @param string $page
660
+     */
661
+    public static function registerPersonal($app, $page) {
662
+        self::$personalForms[] = $app . '/' . $page . '.php';
663
+    }
664
+
665
+    /**
666
+     * @param array $entry
667
+     */
668
+    public static function registerLogIn(array $entry) {
669
+        self::$altLogin[] = $entry;
670
+    }
671
+
672
+    /**
673
+     * @return array
674
+     */
675
+    public static function getAlternativeLogIns() {
676
+        return self::$altLogin;
677
+    }
678
+
679
+    /**
680
+     * get a list of all apps in the apps folder
681
+     *
682
+     * @return array an array of app names (string IDs)
683
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
684
+     */
685
+    public static function getAllApps() {
686
+
687
+        $apps = array();
688
+
689
+        foreach (OC::$APPSROOTS as $apps_dir) {
690
+            if (!is_readable($apps_dir['path'])) {
691
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
692
+                continue;
693
+            }
694
+            $dh = opendir($apps_dir['path']);
695
+
696
+            if (is_resource($dh)) {
697
+                while (($file = readdir($dh)) !== false) {
698
+
699
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
700
+
701
+                        $apps[] = $file;
702
+                    }
703
+                }
704
+            }
705
+        }
706
+
707
+        $apps = array_unique($apps);
708
+
709
+        return $apps;
710
+    }
711
+
712
+    /**
713
+     * List all apps, this is used in apps.php
714
+     *
715
+     * @return array
716
+     */
717
+    public function listAllApps() {
718
+        $installedApps = OC_App::getAllApps();
719
+
720
+        $appManager = \OC::$server->getAppManager();
721
+        //we don't want to show configuration for these
722
+        $blacklist = $appManager->getAlwaysEnabledApps();
723
+        $appList = array();
724
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
725
+        $urlGenerator = \OC::$server->getURLGenerator();
726
+
727
+        foreach ($installedApps as $app) {
728
+            if (array_search($app, $blacklist) === false) {
729
+
730
+                $info = OC_App::getAppInfo($app, false, $langCode);
731
+                if (!is_array($info)) {
732
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
733
+                    continue;
734
+                }
735
+
736
+                if (!isset($info['name'])) {
737
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
738
+                    continue;
739
+                }
740
+
741
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
742
+                $info['groups'] = null;
743
+                if ($enabled === 'yes') {
744
+                    $active = true;
745
+                } else if ($enabled === 'no') {
746
+                    $active = false;
747
+                } else {
748
+                    $active = true;
749
+                    $info['groups'] = $enabled;
750
+                }
751
+
752
+                $info['active'] = $active;
753
+
754
+                if ($appManager->isShipped($app)) {
755
+                    $info['internal'] = true;
756
+                    $info['level'] = self::officialApp;
757
+                    $info['removable'] = false;
758
+                } else {
759
+                    $info['internal'] = false;
760
+                    $info['removable'] = true;
761
+                }
762
+
763
+                $appPath = self::getAppPath($app);
764
+                if($appPath !== false) {
765
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
766
+                    if (file_exists($appIcon)) {
767
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
768
+                        $info['previewAsIcon'] = true;
769
+                    } else {
770
+                        $appIcon = $appPath . '/img/app.svg';
771
+                        if (file_exists($appIcon)) {
772
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
773
+                            $info['previewAsIcon'] = true;
774
+                        }
775
+                    }
776
+                }
777
+                // fix documentation
778
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
779
+                    foreach ($info['documentation'] as $key => $url) {
780
+                        // If it is not an absolute URL we assume it is a key
781
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
782
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
783
+                            $url = $urlGenerator->linkToDocs($url);
784
+                        }
785
+
786
+                        $info['documentation'][$key] = $url;
787
+                    }
788
+                }
789
+
790
+                $info['version'] = OC_App::getAppVersion($app);
791
+                $appList[] = $info;
792
+            }
793
+        }
794
+
795
+        return $appList;
796
+    }
797
+
798
+    public static function shouldUpgrade($app) {
799
+        $versions = self::getAppVersions();
800
+        $currentVersion = OC_App::getAppVersion($app);
801
+        if ($currentVersion && isset($versions[$app])) {
802
+            $installedVersion = $versions[$app];
803
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
804
+                return true;
805
+            }
806
+        }
807
+        return false;
808
+    }
809
+
810
+    /**
811
+     * Adjust the number of version parts of $version1 to match
812
+     * the number of version parts of $version2.
813
+     *
814
+     * @param string $version1 version to adjust
815
+     * @param string $version2 version to take the number of parts from
816
+     * @return string shortened $version1
817
+     */
818
+    private static function adjustVersionParts($version1, $version2) {
819
+        $version1 = explode('.', $version1);
820
+        $version2 = explode('.', $version2);
821
+        // reduce $version1 to match the number of parts in $version2
822
+        while (count($version1) > count($version2)) {
823
+            array_pop($version1);
824
+        }
825
+        // if $version1 does not have enough parts, add some
826
+        while (count($version1) < count($version2)) {
827
+            $version1[] = '0';
828
+        }
829
+        return implode('.', $version1);
830
+    }
831
+
832
+    /**
833
+     * Check whether the current ownCloud version matches the given
834
+     * application's version requirements.
835
+     *
836
+     * The comparison is made based on the number of parts that the
837
+     * app info version has. For example for ownCloud 6.0.3 if the
838
+     * app info version is expecting version 6.0, the comparison is
839
+     * made on the first two parts of the ownCloud version.
840
+     * This means that it's possible to specify "requiremin" => 6
841
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
842
+     *
843
+     * @param string $ocVersion ownCloud version to check against
844
+     * @param array $appInfo app info (from xml)
845
+     *
846
+     * @return boolean true if compatible, otherwise false
847
+     */
848
+    public static function isAppCompatible($ocVersion, $appInfo) {
849
+        $requireMin = '';
850
+        $requireMax = '';
851
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
852
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
853
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
854
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
855
+        } else if (isset($appInfo['requiremin'])) {
856
+            $requireMin = $appInfo['requiremin'];
857
+        } else if (isset($appInfo['require'])) {
858
+            $requireMin = $appInfo['require'];
859
+        }
860
+
861
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
862
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
863
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
864
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
865
+        } else if (isset($appInfo['requiremax'])) {
866
+            $requireMax = $appInfo['requiremax'];
867
+        }
868
+
869
+        if (is_array($ocVersion)) {
870
+            $ocVersion = implode('.', $ocVersion);
871
+        }
872
+
873
+        if (!empty($requireMin)
874
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
875
+        ) {
876
+
877
+            return false;
878
+        }
879
+
880
+        if (!empty($requireMax)
881
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
882
+        ) {
883
+            return false;
884
+        }
885
+
886
+        return true;
887
+    }
888
+
889
+    /**
890
+     * get the installed version of all apps
891
+     */
892
+    public static function getAppVersions() {
893
+        static $versions;
894
+
895
+        if(!$versions) {
896
+            $appConfig = \OC::$server->getAppConfig();
897
+            $versions = $appConfig->getValues(false, 'installed_version');
898
+        }
899
+        return $versions;
900
+    }
901
+
902
+    /**
903
+     * update the database for the app and call the update script
904
+     *
905
+     * @param string $appId
906
+     * @return bool
907
+     */
908
+    public static function updateApp($appId) {
909
+        $appPath = self::getAppPath($appId);
910
+        if($appPath === false) {
911
+            return false;
912
+        }
913
+        self::registerAutoloading($appId, $appPath);
914
+
915
+        $appData = self::getAppInfo($appId);
916
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
917
+
918
+        if (file_exists($appPath . '/appinfo/database.xml')) {
919
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
920
+        } else {
921
+            $ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
922
+            $ms->migrate();
923
+        }
924
+
925
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
926
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
927
+        // update appversion in app manager
928
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
929
+
930
+        // run upgrade code
931
+        if (file_exists($appPath . '/appinfo/update.php')) {
932
+            self::loadApp($appId);
933
+            include $appPath . '/appinfo/update.php';
934
+        }
935
+        self::setupBackgroundJobs($appData['background-jobs']);
936
+
937
+        //set remote/public handlers
938
+        if (array_key_exists('ocsid', $appData)) {
939
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
940
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
941
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
942
+        }
943
+        foreach ($appData['remote'] as $name => $path) {
944
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
945
+        }
946
+        foreach ($appData['public'] as $name => $path) {
947
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
948
+        }
949
+
950
+        self::setAppTypes($appId);
951
+
952
+        $version = \OC_App::getAppVersion($appId);
953
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
954
+
955
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
956
+            ManagerEvent::EVENT_APP_UPDATE, $appId
957
+        ));
958
+
959
+        return true;
960
+    }
961
+
962
+    /**
963
+     * @param string $appId
964
+     * @param string[] $steps
965
+     * @throws \OC\NeedsUpdateException
966
+     */
967
+    public static function executeRepairSteps($appId, array $steps) {
968
+        if (empty($steps)) {
969
+            return;
970
+        }
971
+        // load the app
972
+        self::loadApp($appId);
973
+
974
+        $dispatcher = OC::$server->getEventDispatcher();
975
+
976
+        // load the steps
977
+        $r = new Repair([], $dispatcher);
978
+        foreach ($steps as $step) {
979
+            try {
980
+                $r->addStep($step);
981
+            } catch (Exception $ex) {
982
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
983
+                \OC::$server->getLogger()->logException($ex);
984
+            }
985
+        }
986
+        // run the steps
987
+        $r->run();
988
+    }
989
+
990
+    public static function setupBackgroundJobs(array $jobs) {
991
+        $queue = \OC::$server->getJobList();
992
+        foreach ($jobs as $job) {
993
+            $queue->add($job);
994
+        }
995
+    }
996
+
997
+    /**
998
+     * @param string $appId
999
+     * @param string[] $steps
1000
+     */
1001
+    private static function setupLiveMigrations($appId, array $steps) {
1002
+        $queue = \OC::$server->getJobList();
1003
+        foreach ($steps as $step) {
1004
+            $queue->add('OC\Migration\BackgroundRepair', [
1005
+                'app' => $appId,
1006
+                'step' => $step]);
1007
+        }
1008
+    }
1009
+
1010
+    /**
1011
+     * @param string $appId
1012
+     * @return \OC\Files\View|false
1013
+     */
1014
+    public static function getStorage($appId) {
1015
+        if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1016
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1017
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1018
+                if (!$view->file_exists($appId)) {
1019
+                    $view->mkdir($appId);
1020
+                }
1021
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1022
+            } else {
1023
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1024
+                return false;
1025
+            }
1026
+        } else {
1027
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1028
+            return false;
1029
+        }
1030
+    }
1031
+
1032
+    protected static function findBestL10NOption($options, $lang) {
1033
+        $fallback = $similarLangFallback = $englishFallback = false;
1034
+
1035
+        $lang = strtolower($lang);
1036
+        $similarLang = $lang;
1037
+        if (strpos($similarLang, '_')) {
1038
+            // For "de_DE" we want to find "de" and the other way around
1039
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1040
+        }
1041
+
1042
+        foreach ($options as $option) {
1043
+            if (is_array($option)) {
1044
+                if ($fallback === false) {
1045
+                    $fallback = $option['@value'];
1046
+                }
1047
+
1048
+                if (!isset($option['@attributes']['lang'])) {
1049
+                    continue;
1050
+                }
1051
+
1052
+                $attributeLang = strtolower($option['@attributes']['lang']);
1053
+                if ($attributeLang === $lang) {
1054
+                    return $option['@value'];
1055
+                }
1056
+
1057
+                if ($attributeLang === $similarLang) {
1058
+                    $similarLangFallback = $option['@value'];
1059
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1060
+                    if ($similarLangFallback === false) {
1061
+                        $similarLangFallback =  $option['@value'];
1062
+                    }
1063
+                }
1064
+            } else {
1065
+                $englishFallback = $option;
1066
+            }
1067
+        }
1068
+
1069
+        if ($similarLangFallback !== false) {
1070
+            return $similarLangFallback;
1071
+        } else if ($englishFallback !== false) {
1072
+            return $englishFallback;
1073
+        }
1074
+        return (string) $fallback;
1075
+    }
1076
+
1077
+    /**
1078
+     * parses the app data array and enhanced the 'description' value
1079
+     *
1080
+     * @param array $data the app data
1081
+     * @param string $lang
1082
+     * @return array improved app data
1083
+     */
1084
+    public static function parseAppInfo(array $data, $lang = null) {
1085
+
1086
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1087
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1088
+        }
1089
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1090
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1091
+        }
1092
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1093
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1094
+        } else if (isset($data['description']) && is_string($data['description'])) {
1095
+            $data['description'] = trim($data['description']);
1096
+        } else  {
1097
+            $data['description'] = '';
1098
+        }
1099
+
1100
+        return $data;
1101
+    }
1102
+
1103
+    /**
1104
+     * @param \OCP\IConfig $config
1105
+     * @param \OCP\IL10N $l
1106
+     * @param array $info
1107
+     * @throws \Exception
1108
+     */
1109
+    public static function checkAppDependencies($config, $l, $info) {
1110
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1111
+        $missing = $dependencyAnalyzer->analyze($info);
1112
+        if (!empty($missing)) {
1113
+            $missingMsg = implode(PHP_EOL, $missing);
1114
+            throw new \Exception(
1115
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1116
+                    [$info['name'], $missingMsg]
1117
+                )
1118
+            );
1119
+        }
1120
+    }
1121 1121
 }
Please login to merge, or discard this patch.
Spacing   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -110,9 +110,9 @@  discard block
 block discarded – undo
110 110
 		$apps = self::getEnabledApps();
111 111
 
112 112
 		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
113
+		foreach ($apps as $app) {
114 114
 			$path = self::getAppPath($app);
115
-			if($path !== false) {
115
+			if ($path !== false) {
116 116
 				self::registerAutoloading($app, $path);
117 117
 			}
118 118
 		}
@@ -137,17 +137,17 @@  discard block
 block discarded – undo
137 137
 	public static function loadApp($app) {
138 138
 		self::$loadedApps[] = $app;
139 139
 		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
140
+		if ($appPath === false) {
141 141
 			return;
142 142
 		}
143 143
 
144 144
 		// in case someone calls loadApp() directly
145 145
 		self::registerAutoloading($app, $appPath);
146 146
 
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
147
+		if (is_file($appPath.'/appinfo/app.php')) {
148
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
149 149
 			self::requireAppFile($app);
150
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
150
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
151 151
 		}
152 152
 
153 153
 		$info = self::getAppInfo($app);
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
 			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
194 194
 				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
195 195
 			foreach ($plugins as $plugin) {
196
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
196
+				if ($plugin['@attributes']['type'] === 'collaborator-search') {
197 197
 					$pluginInfo = [
198 198
 						'shareType' => $plugin['@attributes']['share-type'],
199 199
 						'class' => $plugin['@value'],
@@ -212,8 +212,8 @@  discard block
 block discarded – undo
212 212
 	 * @param string $path
213 213
 	 */
214 214
 	public static function registerAutoloading($app, $path) {
215
-		$key = $app . '-' . $path;
216
-		if(isset(self::$alreadyRegistered[$key])) {
215
+		$key = $app.'-'.$path;
216
+		if (isset(self::$alreadyRegistered[$key])) {
217 217
 			return;
218 218
 		}
219 219
 
@@ -223,17 +223,17 @@  discard block
 block discarded – undo
223 223
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
224 224
 		\OC::$server->registerNamespace($app, $appNamespace);
225 225
 
226
-		if (file_exists($path . '/composer/autoload.php')) {
227
-			require_once $path . '/composer/autoload.php';
226
+		if (file_exists($path.'/composer/autoload.php')) {
227
+			require_once $path.'/composer/autoload.php';
228 228
 		} else {
229
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
229
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
230 230
 			// Register on legacy autoloader
231 231
 			\OC::$loader->addValidRoot($path);
232 232
 		}
233 233
 
234 234
 		// Register Test namespace only when testing
235 235
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
236
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
236
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
237 237
 		}
238 238
 	}
239 239
 
@@ -245,7 +245,7 @@  discard block
 block discarded – undo
245 245
 	private static function requireAppFile($app) {
246 246
 		try {
247 247
 			// encapsulated here to avoid variable scope conflicts
248
-			require_once $app . '/appinfo/app.php';
248
+			require_once $app.'/appinfo/app.php';
249 249
 		} catch (Error $ex) {
250 250
 			\OC::$server->getLogger()->logException($ex);
251 251
 			if (!\OC::$server->getAppManager()->isShipped($app)) {
@@ -299,7 +299,7 @@  discard block
 block discarded – undo
299 299
 	 */
300 300
 	public static function setAppTypes($app) {
301 301
 		$appData = self::getAppInfo($app);
302
-		if(!is_array($appData)) {
302
+		if (!is_array($appData)) {
303 303
 			return;
304 304
 		}
305 305
 
@@ -346,8 +346,8 @@  discard block
 block discarded – undo
346 346
 		} else {
347 347
 			$apps = $appManager->getEnabledAppsForUser($user);
348 348
 		}
349
-		$apps = array_filter($apps, function ($app) {
350
-			return $app !== 'files';//we add this manually
349
+		$apps = array_filter($apps, function($app) {
350
+			return $app !== 'files'; //we add this manually
351 351
 		});
352 352
 		sort($apps);
353 353
 		array_unshift($apps, 'files');
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 		$installer = \OC::$server->query(Installer::class);
385 385
 		$isDownloaded = $installer->isDownloaded($appId);
386 386
 
387
-		if(!$isDownloaded) {
387
+		if (!$isDownloaded) {
388 388
 			$installer->downloadApp($appId);
389 389
 		}
390 390
 
@@ -460,7 +460,7 @@  discard block
 block discarded – undo
460 460
 	 */
461 461
 	public static function findAppInDirectories($appId) {
462 462
 		$sanitizedAppId = self::cleanAppId($appId);
463
-		if($sanitizedAppId !== $appId) {
463
+		if ($sanitizedAppId !== $appId) {
464 464
 			return false;
465 465
 		}
466 466
 		static $app_dir = array();
@@ -471,7 +471,7 @@  discard block
 block discarded – undo
471 471
 
472 472
 		$possibleApps = array();
473 473
 		foreach (OC::$APPSROOTS as $dir) {
474
-			if (file_exists($dir['path'] . '/' . $appId)) {
474
+			if (file_exists($dir['path'].'/'.$appId)) {
475 475
 				$possibleApps[] = $dir;
476 476
 			}
477 477
 		}
@@ -512,7 +512,7 @@  discard block
 block discarded – undo
512 512
 		}
513 513
 
514 514
 		if (($dir = self::findAppInDirectories($appId)) != false) {
515
-			return $dir['path'] . '/' . $appId;
515
+			return $dir['path'].'/'.$appId;
516 516
 		}
517 517
 		return false;
518 518
 	}
@@ -526,7 +526,7 @@  discard block
 block discarded – undo
526 526
 	 */
527 527
 	public static function getAppWebPath($appId) {
528 528
 		if (($dir = self::findAppInDirectories($appId)) != false) {
529
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
529
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
530 530
 		}
531 531
 		return false;
532 532
 	}
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
 	 * @return string
551 551
 	 */
552 552
 	public static function getAppVersionByPath($path) {
553
-		$infoFile = $path . '/appinfo/info.xml';
553
+		$infoFile = $path.'/appinfo/info.xml';
554 554
 		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
555 555
 		return isset($appData['version']) ? $appData['version'] : '';
556 556
 	}
@@ -650,7 +650,7 @@  discard block
 block discarded – undo
650 650
 	 * @param string $page
651 651
 	 */
652 652
 	public static function registerAdmin($app, $page) {
653
-		self::$adminForms[] = $app . '/' . $page . '.php';
653
+		self::$adminForms[] = $app.'/'.$page.'.php';
654 654
 	}
655 655
 
656 656
 	/**
@@ -659,7 +659,7 @@  discard block
 block discarded – undo
659 659
 	 * @param string $page
660 660
 	 */
661 661
 	public static function registerPersonal($app, $page) {
662
-		self::$personalForms[] = $app . '/' . $page . '.php';
662
+		self::$personalForms[] = $app.'/'.$page.'.php';
663 663
 	}
664 664
 
665 665
 	/**
@@ -688,7 +688,7 @@  discard block
 block discarded – undo
688 688
 
689 689
 		foreach (OC::$APPSROOTS as $apps_dir) {
690 690
 			if (!is_readable($apps_dir['path'])) {
691
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
691
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
692 692
 				continue;
693 693
 			}
694 694
 			$dh = opendir($apps_dir['path']);
@@ -696,7 +696,7 @@  discard block
 block discarded – undo
696 696
 			if (is_resource($dh)) {
697 697
 				while (($file = readdir($dh)) !== false) {
698 698
 
699
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
699
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
700 700
 
701 701
 						$apps[] = $file;
702 702
 					}
@@ -729,12 +729,12 @@  discard block
 block discarded – undo
729 729
 
730 730
 				$info = OC_App::getAppInfo($app, false, $langCode);
731 731
 				if (!is_array($info)) {
732
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
732
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
733 733
 					continue;
734 734
 				}
735 735
 
736 736
 				if (!isset($info['name'])) {
737
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
737
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
738 738
 					continue;
739 739
 				}
740 740
 
@@ -761,13 +761,13 @@  discard block
 block discarded – undo
761 761
 				}
762 762
 
763 763
 				$appPath = self::getAppPath($app);
764
-				if($appPath !== false) {
765
-					$appIcon = $appPath . '/img/' . $app . '.svg';
764
+				if ($appPath !== false) {
765
+					$appIcon = $appPath.'/img/'.$app.'.svg';
766 766
 					if (file_exists($appIcon)) {
767
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
767
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
768 768
 						$info['previewAsIcon'] = true;
769 769
 					} else {
770
-						$appIcon = $appPath . '/img/app.svg';
770
+						$appIcon = $appPath.'/img/app.svg';
771 771
 						if (file_exists($appIcon)) {
772 772
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
773 773
 							$info['previewAsIcon'] = true;
@@ -892,7 +892,7 @@  discard block
 block discarded – undo
892 892
 	public static function getAppVersions() {
893 893
 		static $versions;
894 894
 
895
-		if(!$versions) {
895
+		if (!$versions) {
896 896
 			$appConfig = \OC::$server->getAppConfig();
897 897
 			$versions = $appConfig->getValues(false, 'installed_version');
898 898
 		}
@@ -907,7 +907,7 @@  discard block
 block discarded – undo
907 907
 	 */
908 908
 	public static function updateApp($appId) {
909 909
 		$appPath = self::getAppPath($appId);
910
-		if($appPath === false) {
910
+		if ($appPath === false) {
911 911
 			return false;
912 912
 		}
913 913
 		self::registerAutoloading($appId, $appPath);
@@ -915,8 +915,8 @@  discard block
 block discarded – undo
915 915
 		$appData = self::getAppInfo($appId);
916 916
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
917 917
 
918
-		if (file_exists($appPath . '/appinfo/database.xml')) {
919
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
918
+		if (file_exists($appPath.'/appinfo/database.xml')) {
919
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
920 920
 		} else {
921 921
 			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
922 922
 			$ms->migrate();
@@ -928,23 +928,23 @@  discard block
 block discarded – undo
928 928
 		\OC::$server->getAppManager()->getAppVersion($appId, false);
929 929
 
930 930
 		// run upgrade code
931
-		if (file_exists($appPath . '/appinfo/update.php')) {
931
+		if (file_exists($appPath.'/appinfo/update.php')) {
932 932
 			self::loadApp($appId);
933
-			include $appPath . '/appinfo/update.php';
933
+			include $appPath.'/appinfo/update.php';
934 934
 		}
935 935
 		self::setupBackgroundJobs($appData['background-jobs']);
936 936
 
937 937
 		//set remote/public handlers
938 938
 		if (array_key_exists('ocsid', $appData)) {
939 939
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
940
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
940
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
941 941
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
942 942
 		}
943 943
 		foreach ($appData['remote'] as $name => $path) {
944
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
944
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
945 945
 		}
946 946
 		foreach ($appData['public'] as $name => $path) {
947
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
947
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
948 948
 		}
949 949
 
950 950
 		self::setAppTypes($appId);
@@ -1014,17 +1014,17 @@  discard block
 block discarded – undo
1014 1014
 	public static function getStorage($appId) {
1015 1015
 		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1016 1016
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1017
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1017
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1018 1018
 				if (!$view->file_exists($appId)) {
1019 1019
 					$view->mkdir($appId);
1020 1020
 				}
1021
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1021
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1022 1022
 			} else {
1023
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1023
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1024 1024
 				return false;
1025 1025
 			}
1026 1026
 		} else {
1027
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1027
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1028 1028
 			return false;
1029 1029
 		}
1030 1030
 	}
@@ -1056,9 +1056,9 @@  discard block
 block discarded – undo
1056 1056
 
1057 1057
 				if ($attributeLang === $similarLang) {
1058 1058
 					$similarLangFallback = $option['@value'];
1059
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1059
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1060 1060
 					if ($similarLangFallback === false) {
1061
-						$similarLangFallback =  $option['@value'];
1061
+						$similarLangFallback = $option['@value'];
1062 1062
 					}
1063 1063
 				}
1064 1064
 			} else {
@@ -1093,7 +1093,7 @@  discard block
 block discarded – undo
1093 1093
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1094 1094
 		} else if (isset($data['description']) && is_string($data['description'])) {
1095 1095
 			$data['description'] = trim($data['description']);
1096
-		} else  {
1096
+		} else {
1097 1097
 			$data['description'] = '';
1098 1098
 		}
1099 1099
 
Please login to merge, or discard this patch.
lib/private/App/AppManager.php 1 patch
Indentation   +407 added lines, -407 removed lines patch added patch discarded remove patch
@@ -44,411 +44,411 @@
 block discarded – undo
44 44
 
45 45
 class AppManager implements IAppManager {
46 46
 
47
-	/**
48
-	 * Apps with these types can not be enabled for certain groups only
49
-	 * @var string[]
50
-	 */
51
-	protected $protectedAppTypes = [
52
-		'filesystem',
53
-		'prelogin',
54
-		'authentication',
55
-		'logging',
56
-		'prevent_group_restriction',
57
-	];
58
-
59
-	/** @var IUserSession */
60
-	private $userSession;
61
-
62
-	/** @var AppConfig */
63
-	private $appConfig;
64
-
65
-	/** @var IGroupManager */
66
-	private $groupManager;
67
-
68
-	/** @var ICacheFactory */
69
-	private $memCacheFactory;
70
-
71
-	/** @var EventDispatcherInterface */
72
-	private $dispatcher;
73
-
74
-	/** @var string[] $appId => $enabled */
75
-	private $installedAppsCache;
76
-
77
-	/** @var string[] */
78
-	private $shippedApps;
79
-
80
-	/** @var string[] */
81
-	private $alwaysEnabled;
82
-
83
-	/** @var array */
84
-	private $appInfos = [];
85
-
86
-	/** @var array */
87
-	private $appVersions = [];
88
-
89
-	/**
90
-	 * @param IUserSession $userSession
91
-	 * @param AppConfig $appConfig
92
-	 * @param IGroupManager $groupManager
93
-	 * @param ICacheFactory $memCacheFactory
94
-	 * @param EventDispatcherInterface $dispatcher
95
-	 */
96
-	public function __construct(IUserSession $userSession,
97
-								AppConfig $appConfig,
98
-								IGroupManager $groupManager,
99
-								ICacheFactory $memCacheFactory,
100
-								EventDispatcherInterface $dispatcher) {
101
-		$this->userSession = $userSession;
102
-		$this->appConfig = $appConfig;
103
-		$this->groupManager = $groupManager;
104
-		$this->memCacheFactory = $memCacheFactory;
105
-		$this->dispatcher = $dispatcher;
106
-	}
107
-
108
-	/**
109
-	 * @return string[] $appId => $enabled
110
-	 */
111
-	private function getInstalledAppsValues() {
112
-		if (!$this->installedAppsCache) {
113
-			$values = $this->appConfig->getValues(false, 'enabled');
114
-
115
-			$alwaysEnabledApps = $this->getAlwaysEnabledApps();
116
-			foreach($alwaysEnabledApps as $appId) {
117
-				$values[$appId] = 'yes';
118
-			}
119
-
120
-			$this->installedAppsCache = array_filter($values, function ($value) {
121
-				return $value !== 'no';
122
-			});
123
-			ksort($this->installedAppsCache);
124
-		}
125
-		return $this->installedAppsCache;
126
-	}
127
-
128
-	/**
129
-	 * List all installed apps
130
-	 *
131
-	 * @return string[]
132
-	 */
133
-	public function getInstalledApps() {
134
-		return array_keys($this->getInstalledAppsValues());
135
-	}
136
-
137
-	/**
138
-	 * List all apps enabled for a user
139
-	 *
140
-	 * @param \OCP\IUser $user
141
-	 * @return string[]
142
-	 */
143
-	public function getEnabledAppsForUser(IUser $user) {
144
-		$apps = $this->getInstalledAppsValues();
145
-		$appsForUser = array_filter($apps, function ($enabled) use ($user) {
146
-			return $this->checkAppForUser($enabled, $user);
147
-		});
148
-		return array_keys($appsForUser);
149
-	}
150
-
151
-	/**
152
-	 * Check if an app is enabled for user
153
-	 *
154
-	 * @param string $appId
155
-	 * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used
156
-	 * @return bool
157
-	 */
158
-	public function isEnabledForUser($appId, $user = null) {
159
-		if ($this->isAlwaysEnabled($appId)) {
160
-			return true;
161
-		}
162
-		if ($user === null) {
163
-			$user = $this->userSession->getUser();
164
-		}
165
-		$installedApps = $this->getInstalledAppsValues();
166
-		if (isset($installedApps[$appId])) {
167
-			return $this->checkAppForUser($installedApps[$appId], $user);
168
-		} else {
169
-			return false;
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * @param string $enabled
175
-	 * @param IUser $user
176
-	 * @return bool
177
-	 */
178
-	private function checkAppForUser($enabled, $user) {
179
-		if ($enabled === 'yes') {
180
-			return true;
181
-		} elseif ($user === null) {
182
-			return false;
183
-		} else {
184
-			if(empty($enabled)){
185
-				return false;
186
-			}
187
-
188
-			$groupIds = json_decode($enabled);
189
-
190
-			if (!is_array($groupIds)) {
191
-				$jsonError = json_last_error();
192
-				\OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
193
-				return false;
194
-			}
195
-
196
-			$userGroups = $this->groupManager->getUserGroupIds($user);
197
-			foreach ($userGroups as $groupId) {
198
-				if (in_array($groupId, $groupIds, true)) {
199
-					return true;
200
-				}
201
-			}
202
-			return false;
203
-		}
204
-	}
205
-
206
-	/**
207
-	 * Check if an app is installed in the instance
208
-	 *
209
-	 * @param string $appId
210
-	 * @return bool
211
-	 */
212
-	public function isInstalled($appId) {
213
-		$installedApps = $this->getInstalledAppsValues();
214
-		return isset($installedApps[$appId]);
215
-	}
216
-
217
-	/**
218
-	 * Enable an app for every user
219
-	 *
220
-	 * @param string $appId
221
-	 * @throws AppPathNotFoundException
222
-	 */
223
-	public function enableApp($appId) {
224
-		// Check if app exists
225
-		$this->getAppPath($appId);
226
-
227
-		$this->installedAppsCache[$appId] = 'yes';
228
-		$this->appConfig->setValue($appId, 'enabled', 'yes');
229
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
230
-			ManagerEvent::EVENT_APP_ENABLE, $appId
231
-		));
232
-		$this->clearAppsCache();
233
-	}
234
-
235
-	/**
236
-	 * Whether a list of types contains a protected app type
237
-	 *
238
-	 * @param string[] $types
239
-	 * @return bool
240
-	 */
241
-	public function hasProtectedAppType($types) {
242
-		if (empty($types)) {
243
-			return false;
244
-		}
245
-
246
-		$protectedTypes = array_intersect($this->protectedAppTypes, $types);
247
-		return !empty($protectedTypes);
248
-	}
249
-
250
-	/**
251
-	 * Enable an app only for specific groups
252
-	 *
253
-	 * @param string $appId
254
-	 * @param \OCP\IGroup[] $groups
255
-	 * @throws \Exception if app can't be enabled for groups
256
-	 */
257
-	public function enableAppForGroups($appId, $groups) {
258
-		$info = $this->getAppInfo($appId);
259
-		if (!empty($info['types'])) {
260
-			$protectedTypes = array_intersect($this->protectedAppTypes, $info['types']);
261
-			if (!empty($protectedTypes)) {
262
-				throw new \Exception("$appId can't be enabled for groups.");
263
-			}
264
-		}
265
-
266
-		$groupIds = array_map(function ($group) {
267
-			/** @var \OCP\IGroup $group */
268
-			return $group->getGID();
269
-		}, $groups);
270
-		$this->installedAppsCache[$appId] = json_encode($groupIds);
271
-		$this->appConfig->setValue($appId, 'enabled', json_encode($groupIds));
272
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
273
-			ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
274
-		));
275
-		$this->clearAppsCache();
276
-	}
277
-
278
-	/**
279
-	 * Disable an app for every user
280
-	 *
281
-	 * @param string $appId
282
-	 * @throws \Exception if app can't be disabled
283
-	 */
284
-	public function disableApp($appId) {
285
-		if ($this->isAlwaysEnabled($appId)) {
286
-			throw new \Exception("$appId can't be disabled.");
287
-		}
288
-		unset($this->installedAppsCache[$appId]);
289
-		$this->appConfig->setValue($appId, 'enabled', 'no');
290
-
291
-		// run uninstall steps
292
-		$appData = $this->getAppInfo($appId);
293
-		if (!is_null($appData)) {
294
-			\OC_App::executeRepairSteps($appId, $appData['repair-steps']['uninstall']);
295
-		}
296
-
297
-		// emit disable hook - needed anymore ?
298
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $appId));
299
-
300
-		$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
301
-			ManagerEvent::EVENT_APP_DISABLE, $appId
302
-		));
303
-		$this->clearAppsCache();
304
-	}
305
-
306
-	/**
307
-	 * Get the directory for the given app.
308
-	 *
309
-	 * @param string $appId
310
-	 * @return string
311
-	 * @throws AppPathNotFoundException if app folder can't be found
312
-	 */
313
-	public function getAppPath($appId) {
314
-		$appPath = \OC_App::getAppPath($appId);
315
-		if($appPath === false) {
316
-			throw new AppPathNotFoundException('Could not find path for ' . $appId);
317
-		}
318
-		return $appPath;
319
-	}
320
-
321
-	/**
322
-	 * Clear the cached list of apps when enabling/disabling an app
323
-	 */
324
-	public function clearAppsCache() {
325
-		$settingsMemCache = $this->memCacheFactory->createDistributed('settings');
326
-		$settingsMemCache->clear('listApps');
327
-	}
328
-
329
-	/**
330
-	 * Returns a list of apps that need upgrade
331
-	 *
332
-	 * @param string $version Nextcloud version as array of version components
333
-	 * @return array list of app info from apps that need an upgrade
334
-	 *
335
-	 * @internal
336
-	 */
337
-	public function getAppsNeedingUpgrade($version) {
338
-		$appsToUpgrade = [];
339
-		$apps = $this->getInstalledApps();
340
-		foreach ($apps as $appId) {
341
-			$appInfo = $this->getAppInfo($appId);
342
-			$appDbVersion = $this->appConfig->getValue($appId, 'installed_version');
343
-			if ($appDbVersion
344
-				&& isset($appInfo['version'])
345
-				&& version_compare($appInfo['version'], $appDbVersion, '>')
346
-				&& \OC_App::isAppCompatible($version, $appInfo)
347
-			) {
348
-				$appsToUpgrade[] = $appInfo;
349
-			}
350
-		}
351
-
352
-		return $appsToUpgrade;
353
-	}
354
-
355
-	/**
356
-	 * Returns the app information from "appinfo/info.xml".
357
-	 *
358
-	 * @param string $appId app id
359
-	 *
360
-	 * @param bool $path
361
-	 * @param null $lang
362
-	 * @return array app info
363
-	 */
364
-	public function getAppInfo(string $appId, bool $path = false, $lang = null) {
365
-		if ($path) {
366
-			$file = $appId;
367
-		} else {
368
-			if ($lang === null && isset($this->appInfos[$appId])) {
369
-				return $this->appInfos[$appId];
370
-			}
371
-			try {
372
-				$appPath = $this->getAppPath($appId);
373
-			} catch (AppPathNotFoundException $e) {
374
-				return null;
375
-			}
376
-			$file = $appPath . '/appinfo/info.xml';
377
-		}
378
-
379
-		$parser = new InfoParser($this->memCacheFactory->createLocal('core.appinfo'));
380
-		$data = $parser->parse($file);
381
-
382
-		if (is_array($data)) {
383
-			$data = \OC_App::parseAppInfo($data, $lang);
384
-		}
385
-
386
-		if ($lang === null) {
387
-			$this->appInfos[$appId] = $data;
388
-		}
389
-
390
-		return $data;
391
-	}
392
-
393
-	public function getAppVersion(string $appId, bool $useCache = true) {
394
-		if(!$useCache || !isset($this->appVersions[$appId])) {
395
-			$appInfo = \OC::$server->getAppManager()->getAppInfo($appId);
396
-			$this->appVersions[$appId] = ($appInfo !== null) ? $appInfo['version'] : '0';
397
-		}
398
-		return $this->appVersions[$appId];
399
-	}
400
-
401
-	/**
402
-	 * Returns a list of apps incompatible with the given version
403
-	 *
404
-	 * @param string $version Nextcloud version as array of version components
405
-	 *
406
-	 * @return array list of app info from incompatible apps
407
-	 *
408
-	 * @internal
409
-	 */
410
-	public function getIncompatibleApps($version) {
411
-		$apps = $this->getInstalledApps();
412
-		$incompatibleApps = array();
413
-		foreach ($apps as $appId) {
414
-			$info = $this->getAppInfo($appId);
415
-			if (!\OC_App::isAppCompatible($version, $info)) {
416
-				$incompatibleApps[] = $info;
417
-			}
418
-		}
419
-		return $incompatibleApps;
420
-	}
421
-
422
-	/**
423
-	 * @inheritdoc
424
-	 */
425
-	public function isShipped($appId) {
426
-		$this->loadShippedJson();
427
-		return in_array($appId, $this->shippedApps, true);
428
-	}
429
-
430
-	private function isAlwaysEnabled($appId) {
431
-		$alwaysEnabled = $this->getAlwaysEnabledApps();
432
-		return in_array($appId, $alwaysEnabled, true);
433
-	}
434
-
435
-	private function loadShippedJson() {
436
-		if ($this->shippedApps === null) {
437
-			$shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
438
-			if (!file_exists($shippedJson)) {
439
-				throw new \Exception("File not found: $shippedJson");
440
-			}
441
-			$content = json_decode(file_get_contents($shippedJson), true);
442
-			$this->shippedApps = $content['shippedApps'];
443
-			$this->alwaysEnabled = $content['alwaysEnabled'];
444
-		}
445
-	}
446
-
447
-	/**
448
-	 * @inheritdoc
449
-	 */
450
-	public function getAlwaysEnabledApps() {
451
-		$this->loadShippedJson();
452
-		return $this->alwaysEnabled;
453
-	}
47
+    /**
48
+     * Apps with these types can not be enabled for certain groups only
49
+     * @var string[]
50
+     */
51
+    protected $protectedAppTypes = [
52
+        'filesystem',
53
+        'prelogin',
54
+        'authentication',
55
+        'logging',
56
+        'prevent_group_restriction',
57
+    ];
58
+
59
+    /** @var IUserSession */
60
+    private $userSession;
61
+
62
+    /** @var AppConfig */
63
+    private $appConfig;
64
+
65
+    /** @var IGroupManager */
66
+    private $groupManager;
67
+
68
+    /** @var ICacheFactory */
69
+    private $memCacheFactory;
70
+
71
+    /** @var EventDispatcherInterface */
72
+    private $dispatcher;
73
+
74
+    /** @var string[] $appId => $enabled */
75
+    private $installedAppsCache;
76
+
77
+    /** @var string[] */
78
+    private $shippedApps;
79
+
80
+    /** @var string[] */
81
+    private $alwaysEnabled;
82
+
83
+    /** @var array */
84
+    private $appInfos = [];
85
+
86
+    /** @var array */
87
+    private $appVersions = [];
88
+
89
+    /**
90
+     * @param IUserSession $userSession
91
+     * @param AppConfig $appConfig
92
+     * @param IGroupManager $groupManager
93
+     * @param ICacheFactory $memCacheFactory
94
+     * @param EventDispatcherInterface $dispatcher
95
+     */
96
+    public function __construct(IUserSession $userSession,
97
+                                AppConfig $appConfig,
98
+                                IGroupManager $groupManager,
99
+                                ICacheFactory $memCacheFactory,
100
+                                EventDispatcherInterface $dispatcher) {
101
+        $this->userSession = $userSession;
102
+        $this->appConfig = $appConfig;
103
+        $this->groupManager = $groupManager;
104
+        $this->memCacheFactory = $memCacheFactory;
105
+        $this->dispatcher = $dispatcher;
106
+    }
107
+
108
+    /**
109
+     * @return string[] $appId => $enabled
110
+     */
111
+    private function getInstalledAppsValues() {
112
+        if (!$this->installedAppsCache) {
113
+            $values = $this->appConfig->getValues(false, 'enabled');
114
+
115
+            $alwaysEnabledApps = $this->getAlwaysEnabledApps();
116
+            foreach($alwaysEnabledApps as $appId) {
117
+                $values[$appId] = 'yes';
118
+            }
119
+
120
+            $this->installedAppsCache = array_filter($values, function ($value) {
121
+                return $value !== 'no';
122
+            });
123
+            ksort($this->installedAppsCache);
124
+        }
125
+        return $this->installedAppsCache;
126
+    }
127
+
128
+    /**
129
+     * List all installed apps
130
+     *
131
+     * @return string[]
132
+     */
133
+    public function getInstalledApps() {
134
+        return array_keys($this->getInstalledAppsValues());
135
+    }
136
+
137
+    /**
138
+     * List all apps enabled for a user
139
+     *
140
+     * @param \OCP\IUser $user
141
+     * @return string[]
142
+     */
143
+    public function getEnabledAppsForUser(IUser $user) {
144
+        $apps = $this->getInstalledAppsValues();
145
+        $appsForUser = array_filter($apps, function ($enabled) use ($user) {
146
+            return $this->checkAppForUser($enabled, $user);
147
+        });
148
+        return array_keys($appsForUser);
149
+    }
150
+
151
+    /**
152
+     * Check if an app is enabled for user
153
+     *
154
+     * @param string $appId
155
+     * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used
156
+     * @return bool
157
+     */
158
+    public function isEnabledForUser($appId, $user = null) {
159
+        if ($this->isAlwaysEnabled($appId)) {
160
+            return true;
161
+        }
162
+        if ($user === null) {
163
+            $user = $this->userSession->getUser();
164
+        }
165
+        $installedApps = $this->getInstalledAppsValues();
166
+        if (isset($installedApps[$appId])) {
167
+            return $this->checkAppForUser($installedApps[$appId], $user);
168
+        } else {
169
+            return false;
170
+        }
171
+    }
172
+
173
+    /**
174
+     * @param string $enabled
175
+     * @param IUser $user
176
+     * @return bool
177
+     */
178
+    private function checkAppForUser($enabled, $user) {
179
+        if ($enabled === 'yes') {
180
+            return true;
181
+        } elseif ($user === null) {
182
+            return false;
183
+        } else {
184
+            if(empty($enabled)){
185
+                return false;
186
+            }
187
+
188
+            $groupIds = json_decode($enabled);
189
+
190
+            if (!is_array($groupIds)) {
191
+                $jsonError = json_last_error();
192
+                \OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
193
+                return false;
194
+            }
195
+
196
+            $userGroups = $this->groupManager->getUserGroupIds($user);
197
+            foreach ($userGroups as $groupId) {
198
+                if (in_array($groupId, $groupIds, true)) {
199
+                    return true;
200
+                }
201
+            }
202
+            return false;
203
+        }
204
+    }
205
+
206
+    /**
207
+     * Check if an app is installed in the instance
208
+     *
209
+     * @param string $appId
210
+     * @return bool
211
+     */
212
+    public function isInstalled($appId) {
213
+        $installedApps = $this->getInstalledAppsValues();
214
+        return isset($installedApps[$appId]);
215
+    }
216
+
217
+    /**
218
+     * Enable an app for every user
219
+     *
220
+     * @param string $appId
221
+     * @throws AppPathNotFoundException
222
+     */
223
+    public function enableApp($appId) {
224
+        // Check if app exists
225
+        $this->getAppPath($appId);
226
+
227
+        $this->installedAppsCache[$appId] = 'yes';
228
+        $this->appConfig->setValue($appId, 'enabled', 'yes');
229
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
230
+            ManagerEvent::EVENT_APP_ENABLE, $appId
231
+        ));
232
+        $this->clearAppsCache();
233
+    }
234
+
235
+    /**
236
+     * Whether a list of types contains a protected app type
237
+     *
238
+     * @param string[] $types
239
+     * @return bool
240
+     */
241
+    public function hasProtectedAppType($types) {
242
+        if (empty($types)) {
243
+            return false;
244
+        }
245
+
246
+        $protectedTypes = array_intersect($this->protectedAppTypes, $types);
247
+        return !empty($protectedTypes);
248
+    }
249
+
250
+    /**
251
+     * Enable an app only for specific groups
252
+     *
253
+     * @param string $appId
254
+     * @param \OCP\IGroup[] $groups
255
+     * @throws \Exception if app can't be enabled for groups
256
+     */
257
+    public function enableAppForGroups($appId, $groups) {
258
+        $info = $this->getAppInfo($appId);
259
+        if (!empty($info['types'])) {
260
+            $protectedTypes = array_intersect($this->protectedAppTypes, $info['types']);
261
+            if (!empty($protectedTypes)) {
262
+                throw new \Exception("$appId can't be enabled for groups.");
263
+            }
264
+        }
265
+
266
+        $groupIds = array_map(function ($group) {
267
+            /** @var \OCP\IGroup $group */
268
+            return $group->getGID();
269
+        }, $groups);
270
+        $this->installedAppsCache[$appId] = json_encode($groupIds);
271
+        $this->appConfig->setValue($appId, 'enabled', json_encode($groupIds));
272
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
273
+            ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
274
+        ));
275
+        $this->clearAppsCache();
276
+    }
277
+
278
+    /**
279
+     * Disable an app for every user
280
+     *
281
+     * @param string $appId
282
+     * @throws \Exception if app can't be disabled
283
+     */
284
+    public function disableApp($appId) {
285
+        if ($this->isAlwaysEnabled($appId)) {
286
+            throw new \Exception("$appId can't be disabled.");
287
+        }
288
+        unset($this->installedAppsCache[$appId]);
289
+        $this->appConfig->setValue($appId, 'enabled', 'no');
290
+
291
+        // run uninstall steps
292
+        $appData = $this->getAppInfo($appId);
293
+        if (!is_null($appData)) {
294
+            \OC_App::executeRepairSteps($appId, $appData['repair-steps']['uninstall']);
295
+        }
296
+
297
+        // emit disable hook - needed anymore ?
298
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $appId));
299
+
300
+        $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
301
+            ManagerEvent::EVENT_APP_DISABLE, $appId
302
+        ));
303
+        $this->clearAppsCache();
304
+    }
305
+
306
+    /**
307
+     * Get the directory for the given app.
308
+     *
309
+     * @param string $appId
310
+     * @return string
311
+     * @throws AppPathNotFoundException if app folder can't be found
312
+     */
313
+    public function getAppPath($appId) {
314
+        $appPath = \OC_App::getAppPath($appId);
315
+        if($appPath === false) {
316
+            throw new AppPathNotFoundException('Could not find path for ' . $appId);
317
+        }
318
+        return $appPath;
319
+    }
320
+
321
+    /**
322
+     * Clear the cached list of apps when enabling/disabling an app
323
+     */
324
+    public function clearAppsCache() {
325
+        $settingsMemCache = $this->memCacheFactory->createDistributed('settings');
326
+        $settingsMemCache->clear('listApps');
327
+    }
328
+
329
+    /**
330
+     * Returns a list of apps that need upgrade
331
+     *
332
+     * @param string $version Nextcloud version as array of version components
333
+     * @return array list of app info from apps that need an upgrade
334
+     *
335
+     * @internal
336
+     */
337
+    public function getAppsNeedingUpgrade($version) {
338
+        $appsToUpgrade = [];
339
+        $apps = $this->getInstalledApps();
340
+        foreach ($apps as $appId) {
341
+            $appInfo = $this->getAppInfo($appId);
342
+            $appDbVersion = $this->appConfig->getValue($appId, 'installed_version');
343
+            if ($appDbVersion
344
+                && isset($appInfo['version'])
345
+                && version_compare($appInfo['version'], $appDbVersion, '>')
346
+                && \OC_App::isAppCompatible($version, $appInfo)
347
+            ) {
348
+                $appsToUpgrade[] = $appInfo;
349
+            }
350
+        }
351
+
352
+        return $appsToUpgrade;
353
+    }
354
+
355
+    /**
356
+     * Returns the app information from "appinfo/info.xml".
357
+     *
358
+     * @param string $appId app id
359
+     *
360
+     * @param bool $path
361
+     * @param null $lang
362
+     * @return array app info
363
+     */
364
+    public function getAppInfo(string $appId, bool $path = false, $lang = null) {
365
+        if ($path) {
366
+            $file = $appId;
367
+        } else {
368
+            if ($lang === null && isset($this->appInfos[$appId])) {
369
+                return $this->appInfos[$appId];
370
+            }
371
+            try {
372
+                $appPath = $this->getAppPath($appId);
373
+            } catch (AppPathNotFoundException $e) {
374
+                return null;
375
+            }
376
+            $file = $appPath . '/appinfo/info.xml';
377
+        }
378
+
379
+        $parser = new InfoParser($this->memCacheFactory->createLocal('core.appinfo'));
380
+        $data = $parser->parse($file);
381
+
382
+        if (is_array($data)) {
383
+            $data = \OC_App::parseAppInfo($data, $lang);
384
+        }
385
+
386
+        if ($lang === null) {
387
+            $this->appInfos[$appId] = $data;
388
+        }
389
+
390
+        return $data;
391
+    }
392
+
393
+    public function getAppVersion(string $appId, bool $useCache = true) {
394
+        if(!$useCache || !isset($this->appVersions[$appId])) {
395
+            $appInfo = \OC::$server->getAppManager()->getAppInfo($appId);
396
+            $this->appVersions[$appId] = ($appInfo !== null) ? $appInfo['version'] : '0';
397
+        }
398
+        return $this->appVersions[$appId];
399
+    }
400
+
401
+    /**
402
+     * Returns a list of apps incompatible with the given version
403
+     *
404
+     * @param string $version Nextcloud version as array of version components
405
+     *
406
+     * @return array list of app info from incompatible apps
407
+     *
408
+     * @internal
409
+     */
410
+    public function getIncompatibleApps($version) {
411
+        $apps = $this->getInstalledApps();
412
+        $incompatibleApps = array();
413
+        foreach ($apps as $appId) {
414
+            $info = $this->getAppInfo($appId);
415
+            if (!\OC_App::isAppCompatible($version, $info)) {
416
+                $incompatibleApps[] = $info;
417
+            }
418
+        }
419
+        return $incompatibleApps;
420
+    }
421
+
422
+    /**
423
+     * @inheritdoc
424
+     */
425
+    public function isShipped($appId) {
426
+        $this->loadShippedJson();
427
+        return in_array($appId, $this->shippedApps, true);
428
+    }
429
+
430
+    private function isAlwaysEnabled($appId) {
431
+        $alwaysEnabled = $this->getAlwaysEnabledApps();
432
+        return in_array($appId, $alwaysEnabled, true);
433
+    }
434
+
435
+    private function loadShippedJson() {
436
+        if ($this->shippedApps === null) {
437
+            $shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
438
+            if (!file_exists($shippedJson)) {
439
+                throw new \Exception("File not found: $shippedJson");
440
+            }
441
+            $content = json_decode(file_get_contents($shippedJson), true);
442
+            $this->shippedApps = $content['shippedApps'];
443
+            $this->alwaysEnabled = $content['alwaysEnabled'];
444
+        }
445
+    }
446
+
447
+    /**
448
+     * @inheritdoc
449
+     */
450
+    public function getAlwaysEnabledApps() {
451
+        $this->loadShippedJson();
452
+        return $this->alwaysEnabled;
453
+    }
454 454
 }
Please login to merge, or discard this patch.