Passed
Push — master ( 223a91...782554 )
by Morris
11:37
created

OC::registerAppRestrictionsHooks()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 1
nop 0
dl 0
loc 18
rs 9.7666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Adam Williamson <[email protected]>
6
 * @author Andreas Fischer <[email protected]>
7
 * @author Arthur Schiwon <[email protected]>
8
 * @author Bart Visscher <[email protected]>
9
 * @author Bernhard Posselt <[email protected]>
10
 * @author Bjoern Schiessle <[email protected]>
11
 * @author Björn Schießle <[email protected]>
12
 * @author Christoph Wurst <[email protected]>
13
 * @author Damjan Georgievski <[email protected]>
14
 * @author davidgumberg <[email protected]>
15
 * @author Florin Peter <[email protected]>
16
 * @author Individual IT Services <[email protected]>
17
 * @author Jakob Sack <[email protected]>
18
 * @author Jan-Christoph Borchardt <[email protected]>
19
 * @author Joachim Sokolowski <[email protected]>
20
 * @author Joas Schilling <[email protected]>
21
 * @author John Molakvoæ (skjnldsv) <[email protected]>
22
 * @author Juan Pablo Villafáñez <[email protected]>
23
 * @author Jörn Friedrich Dreyer <[email protected]>
24
 * @author Ko- <[email protected]>
25
 * @author Lukas Reschke <[email protected]>
26
 * @author Michael Gapczynski <[email protected]>
27
 * @author Morris Jobke <[email protected]>
28
 * @author Owen Winkler <[email protected]>
29
 * @author Phil Davis <[email protected]>
30
 * @author Ramiro Aparicio <[email protected]>
31
 * @author Robin Appelman <[email protected]>
32
 * @author Robin McCorkell <[email protected]>
33
 * @author Roeland Jago Douma <[email protected]>
34
 * @author Sebastian Wessalowski <[email protected]>
35
 * @author Stefan Weil <[email protected]>
36
 * @author Thomas Müller <[email protected]>
37
 * @author Thomas Tanghus <[email protected]>
38
 * @author Vincent Petry <[email protected]>
39
 * @author Volkan Gezer <[email protected]>
40
 *
41
 * @license AGPL-3.0
42
 *
43
 * This code is free software: you can redistribute it and/or modify
44
 * it under the terms of the GNU Affero General Public License, version 3,
45
 * as published by the Free Software Foundation.
46
 *
47
 * This program is distributed in the hope that it will be useful,
48
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
49
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50
 * GNU Affero General Public License for more details.
51
 *
52
 * You should have received a copy of the GNU Affero General Public License, version 3,
53
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
54
 *
55
 */
56
57
use OCP\ILogger;
58
use OCP\Share;
59
use OC\Encryption\HookManager;
60
use OC\Files\Filesystem;
61
use OC\Share20\Hooks;
62
63
require_once 'public/Constants.php';
64
65
/**
66
 * Class that is a namespace for all global OC variables
67
 * No, we can not put this class in its own file because it is used by
68
 * OC_autoload!
69
 */
70
class OC {
71
	/**
72
	 * Associative array for autoloading. classname => filename
73
	 */
74
	public static $CLASSPATH = array();
75
	/**
76
	 * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
77
	 */
78
	public static $SERVERROOT = '';
79
	/**
80
	 * the current request path relative to the Nextcloud root (e.g. files/index.php)
81
	 */
82
	private static $SUBURI = '';
83
	/**
84
	 * the Nextcloud root path for http requests (e.g. nextcloud/)
85
	 */
86
	public static $WEBROOT = '';
87
	/**
88
	 * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
89
	 * web path in 'url'
90
	 */
91
	public static $APPSROOTS = array();
92
93
	/**
94
	 * @var string
95
	 */
96
	public static $configDir;
97
98
	/**
99
	 * requested app
100
	 */
101
	public static $REQUESTEDAPP = '';
102
103
	/**
104
	 * check if Nextcloud runs in cli mode
105
	 */
106
	public static $CLI = false;
107
108
	/**
109
	 * @var \OC\Autoloader $loader
110
	 */
111
	public static $loader = null;
112
113
	/** @var \Composer\Autoload\ClassLoader $composerAutoloader */
114
	public static $composerAutoloader = null;
115
116
	/**
117
	 * @var \OC\Server
118
	 */
119
	public static $server = null;
120
121
	/**
122
	 * @var \OC\Config
123
	 */
124
	private static $config = null;
125
126
	/**
127
	 * @throws \RuntimeException when the 3rdparty directory is missing or
128
	 * the app path list is empty or contains an invalid path
129
	 */
130
	public static function initPaths() {
131
		if(defined('PHPUNIT_CONFIG_DIR')) {
132
			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
0 ignored issues
show
Bug introduced by
The constant PHPUNIT_CONFIG_DIR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
133
		} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
0 ignored issues
show
Bug introduced by
The constant PHPUNIT_RUN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
134
			self::$configDir = OC::$SERVERROOT . '/tests/config/';
135
		} elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
136
			self::$configDir = rtrim($dir, '/') . '/';
137
		} else {
138
			self::$configDir = OC::$SERVERROOT . '/config/';
139
		}
140
		self::$config = new \OC\Config(self::$configDir);
141
142
		OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
143
		/**
144
		 * FIXME: The following lines are required because we can't yet instantiate
145
		 *        \OC::$server->getRequest() since \OC::$server does not yet exist.
146
		 */
147
		$params = [
148
			'server' => [
149
				'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
150
				'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
151
			],
152
		];
153
		$fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
154
		$scriptName = $fakeRequest->getScriptName();
155
		if (substr($scriptName, -1) == '/') {
156
			$scriptName .= 'index.php';
157
			//make sure suburi follows the same rules as scriptName
158
			if (substr(OC::$SUBURI, -9) != 'index.php') {
159
				if (substr(OC::$SUBURI, -1) != '/') {
160
					OC::$SUBURI = OC::$SUBURI . '/';
161
				}
162
				OC::$SUBURI = OC::$SUBURI . 'index.php';
163
			}
164
		}
165
166
167
		if (OC::$CLI) {
168
			OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
169
		} else {
170
			if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
171
				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
172
173
				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
174
					OC::$WEBROOT = '/' . OC::$WEBROOT;
175
				}
176
			} else {
177
				// The scriptName is not ending with OC::$SUBURI
178
				// This most likely means that we are calling from CLI.
179
				// However some cron jobs still need to generate
180
				// a web URL, so we use overwritewebroot as a fallback.
181
				OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
182
			}
183
184
			// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
185
			// slash which is required by URL generation.
186
			if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
187
					substr($_SERVER['REQUEST_URI'], -1) !== '/') {
188
				header('Location: '.\OC::$WEBROOT.'/');
189
				exit();
190
			}
191
		}
192
193
		// search the apps folder
194
		$config_paths = self::$config->getValue('apps_paths', array());
195
		if (!empty($config_paths)) {
196
			foreach ($config_paths as $paths) {
197
				if (isset($paths['url']) && isset($paths['path'])) {
198
					$paths['url'] = rtrim($paths['url'], '/');
199
					$paths['path'] = rtrim($paths['path'], '/');
200
					OC::$APPSROOTS[] = $paths;
201
				}
202
			}
203
		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
204
			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
205
		} elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
206
			OC::$APPSROOTS[] = array(
207
				'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
208
				'url' => '/apps',
209
				'writable' => true
210
			);
211
		}
212
213
		if (empty(OC::$APPSROOTS)) {
214
			throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
215
				. ' or the folder above. You can also configure the location in the config.php file.');
216
		}
217
		$paths = array();
218
		foreach (OC::$APPSROOTS as $path) {
219
			$paths[] = $path['path'];
220
			if (!is_dir($path['path'])) {
221
				throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
222
					. ' Nextcloud folder or the folder above. You can also configure the location in the'
223
					. ' config.php file.', $path['path']));
224
			}
225
		}
226
227
		// set the right include path
228
		set_include_path(
229
			implode(PATH_SEPARATOR, $paths)
230
		);
231
	}
232
233
	public static function checkConfig() {
234
		$l = \OC::$server->getL10N('lib');
235
236
		// Create config if it does not already exist
237
		$configFilePath = self::$configDir .'/config.php';
238
		if(!file_exists($configFilePath)) {
239
			@touch($configFilePath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for touch(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

239
			/** @scrutinizer ignore-unhandled */ @touch($configFilePath);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
240
		}
241
242
		// Check if config is writable
243
		$configFileWritable = is_writable($configFilePath);
244
		if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! $configFileWritable &...OCP\Util::needUpgrade(), Probably Intended Meaning: ! $configFileWritable &&...CP\Util::needUpgrade())
Loading history...
245
			|| !$configFileWritable && \OCP\Util::needUpgrade()) {
246
247
			$urlGenerator = \OC::$server->getURLGenerator();
248
249
			if (self::$CLI) {
250
				echo $l->t('Cannot write into "config" directory!')."\n";
251
				echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
252
				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
253
				echo "\n";
254
				echo $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it.')."\n";
255
				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-config') ])."\n";
256
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
257
			} else {
258
				OC_Template::printErrorPage(
259
					$l->t('Cannot write into "config" directory!'),
260
					$l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
261
					[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
262
					. $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
263
					[ $urlGenerator->linkToDocs('admin-config') ] ),
264
					503
265
				);
266
			}
267
		}
268
	}
269
270
	public static function checkInstalled() {
271
		if (defined('OC_CONSOLE')) {
272
			return;
273
		}
274
		// Redirect to installer if not installed
275
		if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
276
			if (OC::$CLI) {
277
				throw new Exception('Not installed');
278
			} else {
279
				$url = OC::$WEBROOT . '/index.php';
280
				header('Location: ' . $url);
281
			}
282
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
283
		}
284
	}
285
286
	public static function checkMaintenanceMode() {
287
		// Allow ajax update script to execute without being stopped
288
		if (((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) && OC::$SUBURI != '/core/ajax/update.php') {
289
			// send http status 503
290
			http_response_code(503);
291
			header('Retry-After: 120');
292
293
			// render error page
294
			$template = new OC_Template('', 'update.user', 'guest');
295
			OC_Util::addScript('dist/maintenance');
296
			OC_Util::addStyle('core', 'guest');
297
			$template->printPage();
298
			die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
299
		}
300
	}
301
302
	/**
303
	 * Prints the upgrade page
304
	 *
305
	 * @param \OC\SystemConfig $systemConfig
306
	 */
307
	private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
308
		$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
309
		$tooBig = false;
310
		if (!$disableWebUpdater) {
311
			$apps = \OC::$server->getAppManager();
312
			if ($apps->isInstalled('user_ldap')) {
313
				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
314
315
				$result = $qb->select($qb->func()->count('*', 'user_count'))
316
					->from('ldap_user_mapping')
317
					->execute();
318
				$row = $result->fetch();
319
				$result->closeCursor();
320
321
				$tooBig = ($row['user_count'] > 50);
322
			}
323
			if (!$tooBig && $apps->isInstalled('user_saml')) {
324
				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
325
326
				$result = $qb->select($qb->func()->count('*', 'user_count'))
327
					->from('user_saml_users')
328
					->execute();
329
				$row = $result->fetch();
330
				$result->closeCursor();
331
332
				$tooBig = ($row['user_count'] > 50);
333
			}
334
			if (!$tooBig) {
335
				// count users
336
				$stats = \OC::$server->getUserManager()->countUsers();
337
				$totalUsers = array_sum($stats);
338
				$tooBig = ($totalUsers > 50);
339
			}
340
		}
341
		$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
342
			$_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
343
344
		if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
345
			// send http status 503
346
			http_response_code(503);
347
			header('Retry-After: 120');
348
349
			// render error page
350
			$template = new OC_Template('', 'update.use-cli', 'guest');
351
			$template->assign('productName', 'nextcloud'); // for now
352
			$template->assign('version', OC_Util::getVersionString());
353
			$template->assign('tooBig', $tooBig);
354
355
			$template->printPage();
356
			die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
357
		}
358
359
		// check whether this is a core update or apps update
360
		$installedVersion = $systemConfig->getValue('version', '0.0.0');
361
		$currentVersion = implode('.', \OCP\Util::getVersion());
362
363
		// if not a core upgrade, then it's apps upgrade
364
		$isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
365
366
		$oldTheme = $systemConfig->getValue('theme');
367
		$systemConfig->setValue('theme', '');
368
		OC_Util::addScript('config'); // needed for web root
369
		OC_Util::addScript('update');
370
371
		/** @var \OC\App\AppManager $appManager */
372
		$appManager = \OC::$server->getAppManager();
373
374
		$tmpl = new OC_Template('', 'update.admin', 'guest');
375
		$tmpl->assign('version', OC_Util::getVersionString());
376
		$tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
377
378
		// get third party apps
379
		$ocVersion = \OCP\Util::getVersion();
380
		$ocVersion = implode('.', $ocVersion);
381
		$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
382
		$incompatibleShippedApps = [];
383
		foreach ($incompatibleApps as $appInfo) {
384
			if ($appManager->isShipped($appInfo['id'])) {
385
				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
386
			}
387
		}
388
389
		if (!empty($incompatibleShippedApps)) {
390
			$l = \OC::$server->getL10N('core');
391
			$hint = $l->t('The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
392
			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);
393
		}
394
395
		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
396
		$tmpl->assign('incompatibleAppsList', $incompatibleApps);
397
		$tmpl->assign('productName', 'Nextcloud'); // for now
398
		$tmpl->assign('oldTheme', $oldTheme);
399
		$tmpl->printPage();
400
	}
401
402
	public static function initSession() {
403
		if(self::$server->getRequest()->getServerProtocol() === 'https') {
404
			ini_set('session.cookie_secure', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $newvalue of ini_set(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

404
			ini_set('session.cookie_secure', /** @scrutinizer ignore-type */ true);
Loading history...
405
		}
406
407
		// prevents javascript from accessing php session cookies
408
		ini_set('session.cookie_httponly', 'true');
409
410
		// set the cookie path to the Nextcloud directory
411
		$cookie_path = OC::$WEBROOT ? : '/';
412
		ini_set('session.cookie_path', $cookie_path);
413
414
		// Let the session name be changed in the initSession Hook
415
		$sessionName = OC_Util::getInstanceId();
416
417
		try {
418
			// Allow session apps to create a custom session object
419
			$useCustomSession = false;
420
			$session = self::$server->getSession();
421
			OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
422
			if (!$useCustomSession) {
0 ignored issues
show
introduced by
The condition $useCustomSession is always false.
Loading history...
423
				// set the session name to the instance id - which is unique
424
				$session = new \OC\Session\Internal($sessionName);
425
			}
426
427
			$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
428
			$session = $cryptoWrapper->wrapSession($session);
429
			self::$server->setSession($session);
430
431
			// if session can't be started break with http 500 error
432
		} catch (Exception $e) {
433
			\OC::$server->getLogger()->logException($e, ['app' => 'base']);
434
			//show the user a detailed error page
435
			OC_Template::printExceptionErrorPage($e, 500);
436
			die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
437
		}
438
439
		$sessionLifeTime = self::getSessionLifeTime();
440
441
		// session timeout
442
		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
443
			if (isset($_COOKIE[session_name()])) {
444
				setcookie(session_name(), '', -1, self::$WEBROOT ? : '/');
445
			}
446
			\OC::$server->getUserSession()->logout();
447
		}
448
449
		$session->set('LAST_ACTIVITY', time());
450
	}
451
452
	/**
453
	 * @return string
454
	 */
455
	private static function getSessionLifeTime() {
456
		return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
457
	}
458
459
	/**
460
	 * Try to set some values to the required Nextcloud default
461
	 */
462
	public static function setRequiredIniValues() {
463
		@ini_set('default_charset', 'UTF-8');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ini_set(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

463
		/** @scrutinizer ignore-unhandled */ @ini_set('default_charset', 'UTF-8');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
464
		@ini_set('gd.jpeg_ignore_warning', '1');
465
	}
466
467
	/**
468
	 * Send the same site cookies
469
	 */
470
	private static function sendSameSiteCookies() {
471
		$cookieParams = session_get_cookie_params();
472
		$secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
473
		$policies = [
474
			'lax',
475
			'strict',
476
		];
477
478
		// Append __Host to the cookie if it meets the requirements
479
		$cookiePrefix = '';
480
		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
481
			$cookiePrefix = '__Host-';
482
		}
483
484
		foreach($policies as $policy) {
485
			header(
486
				sprintf(
487
					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
488
					$cookiePrefix,
489
					$policy,
490
					$cookieParams['path'],
491
					$policy
492
				),
493
				false
494
			);
495
		}
496
	}
497
498
	/**
499
	 * Same Site cookie to further mitigate CSRF attacks. This cookie has to
500
	 * be set in every request if cookies are sent to add a second level of
501
	 * defense against CSRF.
502
	 *
503
	 * If the cookie is not sent this will set the cookie and reload the page.
504
	 * We use an additional cookie since we want to protect logout CSRF and
505
	 * also we can't directly interfere with PHP's session mechanism.
506
	 */
507
	private static function performSameSiteCookieProtection() {
508
		$request = \OC::$server->getRequest();
509
510
		// Some user agents are notorious and don't really properly follow HTTP
511
		// specifications. For those, have an automated opt-out. Since the protection
512
		// for remote.php is applied in base.php as starting point we need to opt out
513
		// here.
514
		$incompatibleUserAgents = \OC::$server->getConfig()->getSystemValue('csrf.optout');
515
516
		// Fallback, if csrf.optout is unset
517
		if (!is_array($incompatibleUserAgents)) {
518
			$incompatibleUserAgents = [
519
				// OS X Finder
520
				'/^WebDAVFS/',
521
				// Windows webdav drive
522
				'/^Microsoft-WebDAV-MiniRedir/',
523
			];
524
		}
525
526
		if($request->isUserAgent($incompatibleUserAgents)) {
527
			return;
528
		}
529
530
		if(count($_COOKIE) > 0) {
531
			$requestUri = $request->getScriptName();
532
			$processingScript = explode('/', $requestUri);
533
			$processingScript = $processingScript[count($processingScript)-1];
534
535
			// index.php routes are handled in the middleware
536
			if($processingScript === 'index.php') {
537
				return;
538
			}
539
540
			// All other endpoints require the lax and the strict cookie
541
			if(!$request->passesStrictCookieCheck()) {
542
				self::sendSameSiteCookies();
543
				// Debug mode gets access to the resources without strict cookie
544
				// due to the fact that the SabreDAV browser also lives there.
545
				if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
546
					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
547
					exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
548
				}
549
			}
550
		} elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
551
			self::sendSameSiteCookies();
552
		}
553
	}
554
555
	public static function init() {
556
		// calculate the root directories
557
		OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
558
559
		// register autoloader
560
		$loaderStart = microtime(true);
561
		require_once __DIR__ . '/autoloader.php';
562
		self::$loader = new \OC\Autoloader([
563
			OC::$SERVERROOT . '/lib/private/legacy',
564
		]);
565
		if (defined('PHPUNIT_RUN')) {
566
			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
567
		}
568
		spl_autoload_register(array(self::$loader, 'load'));
569
		$loaderEnd = microtime(true);
570
571
		self::$CLI = (php_sapi_name() == 'cli');
572
573
		// Add default composer PSR-4 autoloader
574
		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
575
576
		try {
577
			self::initPaths();
578
			// setup 3rdparty autoloader
579
			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
580
			if (!file_exists($vendorAutoLoad)) {
581
				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".');
582
			}
583
			require_once $vendorAutoLoad;
584
585
		} catch (\RuntimeException $e) {
586
			if (!self::$CLI) {
587
				http_response_code(503);
588
			}
589
			// we can't use the template error page here, because this needs the
590
			// DI container which isn't available yet
591
			print($e->getMessage());
592
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
593
		}
594
595
		// setup the basic server
596
		self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
597
		\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
598
		\OC::$server->getEventLogger()->start('boot', 'Initialize');
599
600
		// Don't display errors and log them
601
		error_reporting(E_ALL | E_STRICT);
602
		@ini_set('display_errors', '0');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ini_set(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

602
		/** @scrutinizer ignore-unhandled */ @ini_set('display_errors', '0');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
603
		@ini_set('log_errors', '1');
604
605
		if(!date_default_timezone_set('UTC')) {
606
			throw new \RuntimeException('Could not set timezone to UTC');
607
		}
608
609
		//try to configure php to enable big file uploads.
610
		//this doesn´t work always depending on the webserver and php configuration.
611
		//Let´s try to overwrite some defaults anyway
612
613
		//try to set the maximum execution time to 60min
614
		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
615
			@set_time_limit(3600);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

615
			/** @scrutinizer ignore-unhandled */ @set_time_limit(3600);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
616
		}
617
		@ini_set('max_execution_time', '3600');
618
		@ini_set('max_input_time', '3600');
619
620
		//try to set the maximum filesize to 10G
621
		@ini_set('upload_max_filesize', '10G');
622
		@ini_set('post_max_size', '10G');
623
		@ini_set('file_uploads', '50');
624
625
		self::setRequiredIniValues();
626
		self::handleAuthHeaders();
627
		self::registerAutoloaderCache();
628
629
		// initialize intl fallback is necessary
630
		\Patchwork\Utf8\Bootup::initIntl();
631
		OC_Util::isSetLocaleWorking();
632
633
		if (!defined('PHPUNIT_RUN')) {
634
			OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
635
			$debug = \OC::$server->getConfig()->getSystemValue('debug', false);
636
			OC\Log\ErrorHandler::register($debug);
637
		}
638
639
		\OC::$server->getEventLogger()->start('init_session', 'Initialize session');
640
		OC_App::loadApps(array('session'));
641
		if (!self::$CLI) {
642
			self::initSession();
643
		}
644
		\OC::$server->getEventLogger()->end('init_session');
645
		self::checkConfig();
646
		self::checkInstalled();
647
648
		OC_Response::addSecurityHeaders();
649
650
		self::performSameSiteCookieProtection();
651
652
		if (!defined('OC_CONSOLE')) {
653
			$errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
654
			if (count($errors) > 0) {
655
				if (self::$CLI) {
656
					// Convert l10n string into regular string for usage in database
657
					$staticErrors = [];
658
					foreach ($errors as $error) {
659
						echo $error['error'] . "\n";
660
						echo $error['hint'] . "\n\n";
661
						$staticErrors[] = [
662
							'error' => (string)$error['error'],
663
							'hint' => (string)$error['hint'],
664
						];
665
					}
666
667
					try {
668
						\OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
669
					} catch (\Exception $e) {
670
						echo('Writing to database failed');
671
					}
672
					exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
673
				} else {
674
					http_response_code(503);
675
					OC_Util::addStyle('guest');
676
					OC_Template::printGuestPage('', 'error', array('errors' => $errors));
677
					exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
678
				}
679
			} elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
680
				\OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
681
			}
682
		}
683
		//try to set the session lifetime
684
		$sessionLifeTime = self::getSessionLifeTime();
685
		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
686
687
		$systemConfig = \OC::$server->getSystemConfig();
688
689
		// User and Groups
690
		if (!$systemConfig->getValue("installed", false)) {
691
			self::$server->getSession()->set('user_id', '');
692
		}
693
694
		OC_User::useBackend(new \OC\User\Database());
695
		\OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
696
697
		// Subscribe to the hook
698
		\OCP\Util::connectHook(
699
			'\OCA\Files_Sharing\API\Server2Server',
700
			'preLoginNameUsedAsUserName',
701
			'\OC\User\Database',
702
			'preLoginNameUsedAsUserName'
703
		);
704
705
		//setup extra user backends
706
		if (!\OCP\Util::needUpgrade()) {
707
			OC_User::setupBackends();
708
		} else {
709
			// Run upgrades in incognito mode
710
			OC_User::setIncognitoMode(true);
711
		}
712
713
		self::registerCleanupHooks();
714
		self::registerFilesystemHooks();
715
		self::registerShareHooks();
716
		self::registerEncryptionWrapper();
717
		self::registerEncryptionHooks();
718
		self::registerAccountHooks();
719
		self::registerResourceCollectionHooks();
720
		self::registerAppRestrictionsHooks();
721
722
		// Make sure that the application class is not loaded before the database is setup
723
		if ($systemConfig->getValue("installed", false)) {
724
			$settings = new \OC\Settings\Application();
725
			$settings->register();
726
		}
727
728
		//make sure temporary files are cleaned up
729
		$tmpManager = \OC::$server->getTempManager();
730
		register_shutdown_function(array($tmpManager, 'clean'));
731
		$lockProvider = \OC::$server->getLockingProvider();
732
		register_shutdown_function(array($lockProvider, 'releaseAll'));
733
734
		// Check whether the sample configuration has been copied
735
		if($systemConfig->getValue('copied_sample_config', false)) {
736
			$l = \OC::$server->getL10N('lib');
737
			OC_Template::printErrorPage(
738
				$l->t('Sample configuration detected'),
739
				$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'),
740
				503
741
			);
742
			return;
743
		}
744
745
		$request = \OC::$server->getRequest();
746
		$host = $request->getInsecureServerHost();
747
		/**
748
		 * if the host passed in headers isn't trusted
749
		 * FIXME: Should not be in here at all :see_no_evil:
750
		 */
751
		if (!OC::$CLI
752
			// overwritehost is always trusted, workaround to not have to make
753
			// \OC\AppFramework\Http\Request::getOverwriteHost public
754
			&& self::$server->getConfig()->getSystemValue('overwritehost') === ''
755
			&& !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
756
			&& self::$server->getConfig()->getSystemValue('installed', false)
757
		) {
758
			// Allow access to CSS resources
759
			$isScssRequest = false;
760
			if(strpos($request->getPathInfo(), '/css/') === 0) {
761
				$isScssRequest = true;
762
			}
763
764
			if(substr($request->getRequestUri(), -11) === '/status.php') {
765
				http_response_code(400);
766
				header('Content-Type: application/json');
767
				echo '{"error": "Trusted domain error.", "code": 15}';
768
				exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
769
			}
770
771
			if (!$isScssRequest) {
772
				http_response_code(400);
773
774
				\OC::$server->getLogger()->info(
775
					'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
776
					[
777
						'app' => 'core',
778
						'remoteAddress' => $request->getRemoteAddress(),
779
						'host' => $host,
780
					]
781
				);
782
783
				$tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
784
				$tmpl->assign('docUrl', \OC::$server->getURLGenerator()->linkToDocs('admin-trusted-domains'));
785
				$tmpl->printPage();
786
787
				exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
788
			}
789
		}
790
		\OC::$server->getEventLogger()->end('boot');
791
	}
792
793
	/**
794
	 * register hooks for the cleanup of cache and bruteforce protection
795
	 */
796
	public static function registerCleanupHooks() {
797
		//don't try to do this before we are properly setup
798
		if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
799
800
			// NOTE: This will be replaced to use OCP
801
			$userSession = self::$server->getUserSession();
802
			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
0 ignored issues
show
Unused Code introduced by
The import $userSession is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
803
				if (!defined('PHPUNIT_RUN')) {
804
					// reset brute force delay for this IP address and username
805
					$uid = \OC::$server->getUserSession()->getUser()->getUID();
806
					$request = \OC::$server->getRequest();
807
					$throttler = \OC::$server->getBruteForceThrottler();
808
					$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
0 ignored issues
show
Bug introduced by
array('user' => $uid) of type array<string,string> is incompatible with the type string expected by parameter $metadata of OC\Security\Bruteforce\Throttler::resetDelay(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

808
					$throttler->resetDelay($request->getRemoteAddress(), 'login', /** @scrutinizer ignore-type */ ['user' => $uid]);
Loading history...
809
				}
810
811
				try {
812
					$cache = new \OC\Cache\File();
813
					$cache->gc();
814
				} catch (\OC\ServerNotAvailableException $e) {
815
					// not a GC exception, pass it on
816
					throw $e;
817
				} catch (\OC\ForbiddenException $e) {
818
					// filesystem blocked for this request, ignore
819
				} catch (\Exception $e) {
820
					// a GC exception should not prevent users from using OC,
821
					// so log the exception
822
					\OC::$server->getLogger()->logException($e, [
823
						'message' => 'Exception when running cache gc.',
824
						'level' => ILogger::WARN,
825
						'app' => 'core',
826
					]);
827
				}
828
			});
829
		}
830
	}
831
832
	private static function registerEncryptionWrapper() {
833
		$manager = self::$server->getEncryptionManager();
834
		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
835
	}
836
837
	private static function registerEncryptionHooks() {
838
		$enabled = self::$server->getEncryptionManager()->isEnabled();
839
		if ($enabled) {
840
			\OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
841
			\OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
842
			\OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
843
			\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
844
		}
845
	}
846
847
	private static function registerAccountHooks() {
848
		$hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
849
		\OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
850
	}
851
852
	private static function registerAppRestrictionsHooks() {
853
		$groupManager = self::$server->query(\OCP\IGroupManager::class);
854
		$groupManager->listen ('\OC\Group', 'postDelete', function (\OCP\IGroup $group) {
855
			$appManager = self::$server->getAppManager();
856
			$apps = $appManager->getEnabledAppsForGroup($group);
857
			foreach ($apps as $appId) {
858
				$restrictions = $appManager->getAppRestriction($appId);
859
				if (empty($restrictions)) {
860
					continue;
861
				}
862
				$key = array_search($group->getGID(), $restrictions);
863
				unset($restrictions[$key]);
864
				$restrictions = array_values($restrictions);
865
				if (empty($restrictions)) {
866
					$appManager->disableApp($appId);
867
				}
868
				else{
869
					$appManager->enableAppForGroups($appId, $restrictions);
870
				}
871
872
			}
873
		});
874
	}
875
876
	private static function registerResourceCollectionHooks() {
877
		\OC\Collaboration\Resources\Listener::register(\OC::$server->getEventDispatcher());
878
	}
879
880
	/**
881
	 * register hooks for the filesystem
882
	 */
883
	public static function registerFilesystemHooks() {
884
		// Check for blacklisted files
885
		OC_Hook::connect('OC_Filesystem', 'write', Filesystem::class, 'isBlacklisted');
886
		OC_Hook::connect('OC_Filesystem', 'rename', Filesystem::class, 'isBlacklisted');
887
	}
888
889
	/**
890
	 * register hooks for sharing
891
	 */
892
	public static function registerShareHooks() {
893
		if (\OC::$server->getSystemConfig()->getValue('installed')) {
894
			OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
895
			OC_Hook::connect('OC_User', 'post_removeFromGroup', Hooks::class, 'post_removeFromGroup');
896
			OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
897
		}
898
	}
899
900
	protected static function registerAutoloaderCache() {
901
		// The class loader takes an optional low-latency cache, which MUST be
902
		// namespaced. The instanceid is used for namespacing, but might be
903
		// unavailable at this point. Furthermore, it might not be possible to
904
		// generate an instanceid via \OC_Util::getInstanceId() because the
905
		// config file may not be writable. As such, we only register a class
906
		// loader cache if instanceid is available without trying to create one.
907
		$instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
908
		if ($instanceId) {
909
			try {
910
				$memcacheFactory = \OC::$server->getMemCacheFactory();
911
				self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
912
			} catch (\Exception $ex) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
913
			}
914
		}
915
	}
916
917
	/**
918
	 * Handle the request
919
	 */
920
	public static function handleRequest() {
921
922
		\OC::$server->getEventLogger()->start('handle_request', 'Handle request');
923
		$systemConfig = \OC::$server->getSystemConfig();
924
925
		// Check if Nextcloud is installed or in maintenance (update) mode
926
		if (!$systemConfig->getValue('installed', false)) {
927
			\OC::$server->getSession()->clear();
928
			$setupHelper = new OC\Setup(
929
				$systemConfig,
930
				\OC::$server->getIniWrapper(),
931
				\OC::$server->getL10N('lib'),
932
				\OC::$server->query(\OCP\Defaults::class),
933
				\OC::$server->getLogger(),
934
				\OC::$server->getSecureRandom(),
935
				\OC::$server->query(\OC\Installer::class)
936
			);
937
			$controller = new OC\Core\Controller\SetupController($setupHelper);
938
			$controller->run($_POST);
939
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
940
		}
941
942
		$request = \OC::$server->getRequest();
943
		$requestPath = $request->getRawPathInfo();
944
		if ($requestPath === '/heartbeat') {
945
			return;
946
		}
947
		if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
948
			self::checkMaintenanceMode();
949
950
			if (\OCP\Util::needUpgrade()) {
951
				if (function_exists('opcache_reset')) {
952
					opcache_reset();
953
				}
954
				if (!((bool) $systemConfig->getValue('maintenance', false))) {
955
					self::printUpgradePage($systemConfig);
956
					exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
957
				}
958
			}
959
		}
960
961
		// emergency app disabling
962
		if ($requestPath === '/disableapp'
963
			&& $request->getMethod() === 'POST'
964
			&& ((array)$request->getParam('appid')) !== ''
965
		) {
966
			\OC_JSON::callCheck();
0 ignored issues
show
Deprecated Code introduced by
The function OC_JSON::callCheck() has been deprecated: Use annotation based CSRF checks from the AppFramework instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

966
			/** @scrutinizer ignore-deprecated */ \OC_JSON::callCheck();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
967
			\OC_JSON::checkAdminUser();
968
			$appIds = (array)$request->getParam('appid');
969
			foreach($appIds as $appId) {
970
				$appId = \OC_App::cleanAppId($appId);
971
				\OC::$server->getAppManager()->disableApp($appId);
972
			}
973
			\OC_JSON::success();
974
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
975
		}
976
977
		// Always load authentication apps
978
		OC_App::loadApps(['authentication']);
979
980
		// Load minimum set of apps
981
		if (!\OCP\Util::needUpgrade()
982
			&& !((bool) $systemConfig->getValue('maintenance', false))) {
983
			// For logged-in users: Load everything
984
			if(\OC::$server->getUserSession()->isLoggedIn()) {
985
				OC_App::loadApps();
986
			} else {
987
				// For guests: Load only filesystem and logging
988
				OC_App::loadApps(array('filesystem', 'logging'));
989
				self::handleLogin($request);
990
			}
991
		}
992
993
		if (!self::$CLI) {
994
			try {
995
				if (!((bool) $systemConfig->getValue('maintenance', false)) && !\OCP\Util::needUpgrade()) {
996
					OC_App::loadApps(array('filesystem', 'logging'));
997
					OC_App::loadApps();
998
				}
999
				OC_Util::setupFS();
1000
				OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Route\IRouter::match() has been deprecated: 9.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1000
				/** @scrutinizer ignore-deprecated */ OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1001
				return;
1002
			} catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
1003
				//header('HTTP/1.0 404 Not Found');
1004
			} catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
1005
				http_response_code(405);
1006
				return;
1007
			}
1008
		}
1009
1010
		// Handle WebDAV
1011
		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
1012
			// not allowed any more to prevent people
1013
			// mounting this root directly.
1014
			// Users need to mount remote.php/webdav instead.
1015
			http_response_code(405);
1016
			return;
1017
		}
1018
1019
		// Someone is logged in
1020
		if (\OC::$server->getUserSession()->isLoggedIn()) {
1021
			OC_App::loadApps();
1022
			OC_User::setupBackends();
1023
			OC_Util::setupFS();
1024
			// FIXME
1025
			// Redirect to default application
1026
			OC_Util::redirectToDefaultPage();
1027
		} else {
1028
			// Not handled and not logged in
1029
			header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1030
		}
1031
	}
1032
1033
	/**
1034
	 * Check login: apache auth, auth token, basic auth
1035
	 *
1036
	 * @param OCP\IRequest $request
1037
	 * @return boolean
1038
	 */
1039
	static function handleLogin(OCP\IRequest $request) {
1040
		$userSession = self::$server->getUserSession();
1041
		if (OC_User::handleApacheAuth()) {
1042
			return true;
1043
		}
1044
		if ($userSession->tryTokenLogin($request)) {
1045
			return true;
1046
		}
1047
		if (isset($_COOKIE['nc_username'])
1048
			&& isset($_COOKIE['nc_token'])
1049
			&& isset($_COOKIE['nc_session_id'])
1050
			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1051
			return true;
1052
		}
1053
		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1054
			return true;
1055
		}
1056
		return false;
1057
	}
1058
1059
	protected static function handleAuthHeaders() {
1060
		//copy http auth headers for apache+php-fcgid work around
1061
		if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1062
			$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1063
		}
1064
1065
		// Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1066
		$vars = array(
1067
			'HTTP_AUTHORIZATION', // apache+php-cgi work around
1068
			'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1069
		);
1070
		foreach ($vars as $var) {
1071
			if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1072
				list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1073
				$_SERVER['PHP_AUTH_USER'] = $name;
1074
				$_SERVER['PHP_AUTH_PW'] = $password;
1075
				break;
1076
			}
1077
		}
1078
	}
1079
}
1080
1081
OC::init();
1082