Completed
Push — master ( 9222dc...c12161 )
by Morris
56:15 queued 36:32
created
lib/private/AppFramework/Http/Request.php 1 patch
Indentation   +809 added lines, -809 removed lines patch added patch discarded remove patch
@@ -58,814 +58,814 @@
 block discarded – undo
58 58
  */
59 59
 class Request implements \ArrayAccess, \Countable, IRequest {
60 60
 
61
-	const USER_AGENT_IE = '/(MSIE)|(Trident)/';
62
-	// Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
63
-	const USER_AGENT_MS_EDGE = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/';
64
-	// Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
65
-	const USER_AGENT_FIREFOX = '/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/[0-9.]+$/';
66
-	// Chrome User Agent from https://developer.chrome.com/multidevice/user-agent
67
-	const USER_AGENT_CHROME = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)( Ubuntu Chromium\/[0-9.]+|) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/';
68
-	// Safari User Agent from http://www.useragentstring.com/pages/Safari/
69
-	const USER_AGENT_SAFARI = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/[0-9.]+ Safari\/[0-9.A-Z]+$/';
70
-	// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
71
-	const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
72
-	const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
73
-	const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|::1)$/';
74
-
75
-	/**
76
-	 * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_IOS instead
77
-	 */
78
-	const USER_AGENT_OWNCLOUD_IOS = '/^Mozilla\/5\.0 \(iOS\) (ownCloud|Nextcloud)\-iOS.*$/';
79
-	/**
80
-	 * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_ANDROID instead
81
-	 */
82
-	const USER_AGENT_OWNCLOUD_ANDROID = '/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/';
83
-	/**
84
-	 * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_DESKTOP instead
85
-	 */
86
-	const USER_AGENT_OWNCLOUD_DESKTOP = '/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/';
87
-
88
-	protected $inputStream;
89
-	protected $content;
90
-	protected $items = array();
91
-	protected $allowedKeys = array(
92
-		'get',
93
-		'post',
94
-		'files',
95
-		'server',
96
-		'env',
97
-		'cookies',
98
-		'urlParams',
99
-		'parameters',
100
-		'method',
101
-		'requesttoken',
102
-	);
103
-	/** @var ISecureRandom */
104
-	protected $secureRandom;
105
-	/** @var IConfig */
106
-	protected $config;
107
-	/** @var string */
108
-	protected $requestId = '';
109
-	/** @var ICrypto */
110
-	protected $crypto;
111
-	/** @var CsrfTokenManager|null */
112
-	protected $csrfTokenManager;
113
-
114
-	/** @var bool */
115
-	protected $contentDecoded = false;
116
-
117
-	/**
118
-	 * @param array $vars An associative array with the following optional values:
119
-	 *        - array 'urlParams' the parameters which were matched from the URL
120
-	 *        - array 'get' the $_GET array
121
-	 *        - array|string 'post' the $_POST array or JSON string
122
-	 *        - array 'files' the $_FILES array
123
-	 *        - array 'server' the $_SERVER array
124
-	 *        - array 'env' the $_ENV array
125
-	 *        - array 'cookies' the $_COOKIE array
126
-	 *        - string 'method' the request method (GET, POST etc)
127
-	 *        - string|false 'requesttoken' the requesttoken or false when not available
128
-	 * @param ISecureRandom $secureRandom
129
-	 * @param IConfig $config
130
-	 * @param CsrfTokenManager|null $csrfTokenManager
131
-	 * @param string $stream
132
-	 * @see http://www.php.net/manual/en/reserved.variables.php
133
-	 */
134
-	public function __construct(array $vars=array(),
135
-								ISecureRandom $secureRandom = null,
136
-								IConfig $config,
137
-								CsrfTokenManager $csrfTokenManager = null,
138
-								$stream = 'php://input') {
139
-		$this->inputStream = $stream;
140
-		$this->items['params'] = array();
141
-		$this->secureRandom = $secureRandom;
142
-		$this->config = $config;
143
-		$this->csrfTokenManager = $csrfTokenManager;
144
-
145
-		if(!array_key_exists('method', $vars)) {
146
-			$vars['method'] = 'GET';
147
-		}
148
-
149
-		foreach($this->allowedKeys as $name) {
150
-			$this->items[$name] = isset($vars[$name])
151
-				? $vars[$name]
152
-				: array();
153
-		}
154
-
155
-		$this->items['parameters'] = array_merge(
156
-			$this->items['get'],
157
-			$this->items['post'],
158
-			$this->items['urlParams'],
159
-			$this->items['params']
160
-		);
161
-
162
-	}
163
-	/**
164
-	 * @param array $parameters
165
-	 */
166
-	public function setUrlParameters(array $parameters) {
167
-		$this->items['urlParams'] = $parameters;
168
-		$this->items['parameters'] = array_merge(
169
-			$this->items['parameters'],
170
-			$this->items['urlParams']
171
-		);
172
-	}
173
-
174
-	/**
175
-	 * Countable method
176
-	 * @return int
177
-	 */
178
-	public function count() {
179
-		return count(array_keys($this->items['parameters']));
180
-	}
181
-
182
-	/**
183
-	* ArrayAccess methods
184
-	*
185
-	* Gives access to the combined GET, POST and urlParams arrays
186
-	*
187
-	* Examples:
188
-	*
189
-	* $var = $request['myvar'];
190
-	*
191
-	* or
192
-	*
193
-	* if(!isset($request['myvar']) {
194
-	* 	// Do something
195
-	* }
196
-	*
197
-	* $request['myvar'] = 'something'; // This throws an exception.
198
-	*
199
-	* @param string $offset The key to lookup
200
-	* @return boolean
201
-	*/
202
-	public function offsetExists($offset) {
203
-		return isset($this->items['parameters'][$offset]);
204
-	}
205
-
206
-	/**
207
-	* @see offsetExists
208
-	*/
209
-	public function offsetGet($offset) {
210
-		return isset($this->items['parameters'][$offset])
211
-			? $this->items['parameters'][$offset]
212
-			: null;
213
-	}
214
-
215
-	/**
216
-	* @see offsetExists
217
-	*/
218
-	public function offsetSet($offset, $value) {
219
-		throw new \RuntimeException('You cannot change the contents of the request object');
220
-	}
221
-
222
-	/**
223
-	* @see offsetExists
224
-	*/
225
-	public function offsetUnset($offset) {
226
-		throw new \RuntimeException('You cannot change the contents of the request object');
227
-	}
228
-
229
-	/**
230
-	 * Magic property accessors
231
-	 * @param string $name
232
-	 * @param mixed $value
233
-	 */
234
-	public function __set($name, $value) {
235
-		throw new \RuntimeException('You cannot change the contents of the request object');
236
-	}
237
-
238
-	/**
239
-	* Access request variables by method and name.
240
-	* Examples:
241
-	*
242
-	* $request->post['myvar']; // Only look for POST variables
243
-	* $request->myvar; or $request->{'myvar'}; or $request->{$myvar}
244
-	* Looks in the combined GET, POST and urlParams array.
245
-	*
246
-	* If you access e.g. ->post but the current HTTP request method
247
-	* is GET a \LogicException will be thrown.
248
-	*
249
-	* @param string $name The key to look for.
250
-	* @throws \LogicException
251
-	* @return mixed|null
252
-	*/
253
-	public function __get($name) {
254
-		switch($name) {
255
-			case 'put':
256
-			case 'patch':
257
-			case 'get':
258
-			case 'post':
259
-				if($this->method !== strtoupper($name)) {
260
-					throw new \LogicException(sprintf('%s cannot be accessed in a %s request.', $name, $this->method));
261
-				}
262
-				return $this->getContent();
263
-			case 'files':
264
-			case 'server':
265
-			case 'env':
266
-			case 'cookies':
267
-			case 'urlParams':
268
-			case 'method':
269
-				return isset($this->items[$name])
270
-					? $this->items[$name]
271
-					: null;
272
-			case 'parameters':
273
-			case 'params':
274
-				return $this->getContent();
275
-			default;
276
-				return isset($this[$name])
277
-					? $this[$name]
278
-					: null;
279
-		}
280
-	}
281
-
282
-	/**
283
-	 * @param string $name
284
-	 * @return bool
285
-	 */
286
-	public function __isset($name) {
287
-		if (in_array($name, $this->allowedKeys, true)) {
288
-			return true;
289
-		}
290
-		return isset($this->items['parameters'][$name]);
291
-	}
292
-
293
-	/**
294
-	 * @param string $id
295
-	 */
296
-	public function __unset($id) {
297
-		throw new \RuntimeException('You cannot change the contents of the request object');
298
-	}
299
-
300
-	/**
301
-	 * Returns the value for a specific http header.
302
-	 *
303
-	 * This method returns null if the header did not exist.
304
-	 *
305
-	 * @param string $name
306
-	 * @return string
307
-	 */
308
-	public function getHeader($name) {
309
-
310
-		$name = strtoupper(str_replace(array('-'),array('_'),$name));
311
-		if (isset($this->server['HTTP_' . $name])) {
312
-			return $this->server['HTTP_' . $name];
313
-		}
314
-
315
-		// There's a few headers that seem to end up in the top-level
316
-		// server array.
317
-		switch($name) {
318
-			case 'CONTENT_TYPE' :
319
-			case 'CONTENT_LENGTH' :
320
-				if (isset($this->server[$name])) {
321
-					return $this->server[$name];
322
-				}
323
-				break;
324
-
325
-		}
326
-
327
-		return '';
328
-	}
329
-
330
-	/**
331
-	 * Lets you access post and get parameters by the index
332
-	 * In case of json requests the encoded json body is accessed
333
-	 *
334
-	 * @param string $key the key which you want to access in the URL Parameter
335
-	 *                     placeholder, $_POST or $_GET array.
336
-	 *                     The priority how they're returned is the following:
337
-	 *                     1. URL parameters
338
-	 *                     2. POST parameters
339
-	 *                     3. GET parameters
340
-	 * @param mixed $default If the key is not found, this value will be returned
341
-	 * @return mixed the content of the array
342
-	 */
343
-	public function getParam($key, $default = null) {
344
-		return isset($this->parameters[$key])
345
-			? $this->parameters[$key]
346
-			: $default;
347
-	}
348
-
349
-	/**
350
-	 * Returns all params that were received, be it from the request
351
-	 * (as GET or POST) or throuh the URL by the route
352
-	 * @return array the array with all parameters
353
-	 */
354
-	public function getParams() {
355
-		return $this->parameters;
356
-	}
357
-
358
-	/**
359
-	 * Returns the method of the request
360
-	 * @return string the method of the request (POST, GET, etc)
361
-	 */
362
-	public function getMethod() {
363
-		return $this->method;
364
-	}
365
-
366
-	/**
367
-	 * Shortcut for accessing an uploaded file through the $_FILES array
368
-	 * @param string $key the key that will be taken from the $_FILES array
369
-	 * @return array the file in the $_FILES element
370
-	 */
371
-	public function getUploadedFile($key) {
372
-		return isset($this->files[$key]) ? $this->files[$key] : null;
373
-	}
374
-
375
-	/**
376
-	 * Shortcut for getting env variables
377
-	 * @param string $key the key that will be taken from the $_ENV array
378
-	 * @return array the value in the $_ENV element
379
-	 */
380
-	public function getEnv($key) {
381
-		return isset($this->env[$key]) ? $this->env[$key] : null;
382
-	}
383
-
384
-	/**
385
-	 * Shortcut for getting cookie variables
386
-	 * @param string $key the key that will be taken from the $_COOKIE array
387
-	 * @return string the value in the $_COOKIE element
388
-	 */
389
-	public function getCookie($key) {
390
-		return isset($this->cookies[$key]) ? $this->cookies[$key] : null;
391
-	}
392
-
393
-	/**
394
-	 * Returns the request body content.
395
-	 *
396
-	 * If the HTTP request method is PUT and the body
397
-	 * not application/x-www-form-urlencoded or application/json a stream
398
-	 * resource is returned, otherwise an array.
399
-	 *
400
-	 * @return array|string|resource The request body content or a resource to read the body stream.
401
-	 *
402
-	 * @throws \LogicException
403
-	 */
404
-	protected function getContent() {
405
-		// If the content can't be parsed into an array then return a stream resource.
406
-		if ($this->method === 'PUT'
407
-			&& $this->getHeader('Content-Length') !== '0'
408
-			&& $this->getHeader('Content-Length') !== ''
409
-			&& strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') === false
410
-			&& strpos($this->getHeader('Content-Type'), 'application/json') === false
411
-		) {
412
-			if ($this->content === false) {
413
-				throw new \LogicException(
414
-					'"put" can only be accessed once if not '
415
-					. 'application/x-www-form-urlencoded or application/json.'
416
-				);
417
-			}
418
-			$this->content = false;
419
-			return fopen($this->inputStream, 'rb');
420
-		} else {
421
-			$this->decodeContent();
422
-			return $this->items['parameters'];
423
-		}
424
-	}
425
-
426
-	/**
427
-	 * Attempt to decode the content and populate parameters
428
-	 */
429
-	protected function decodeContent() {
430
-		if ($this->contentDecoded) {
431
-			return;
432
-		}
433
-		$params = [];
434
-
435
-		// 'application/json' must be decoded manually.
436
-		if (strpos($this->getHeader('Content-Type'), 'application/json') !== false) {
437
-			$params = json_decode(file_get_contents($this->inputStream), true);
438
-			if($params !== null && count($params) > 0) {
439
-				$this->items['params'] = $params;
440
-				if($this->method === 'POST') {
441
-					$this->items['post'] = $params;
442
-				}
443
-			}
444
-
445
-		// Handle application/x-www-form-urlencoded for methods other than GET
446
-		// or post correctly
447
-		} elseif($this->method !== 'GET'
448
-				&& $this->method !== 'POST'
449
-				&& strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') !== false) {
450
-
451
-			parse_str(file_get_contents($this->inputStream), $params);
452
-			if(is_array($params)) {
453
-				$this->items['params'] = $params;
454
-			}
455
-		}
456
-
457
-		if (is_array($params)) {
458
-			$this->items['parameters'] = array_merge($this->items['parameters'], $params);
459
-		}
460
-		$this->contentDecoded = true;
461
-	}
462
-
463
-
464
-	/**
465
-	 * Checks if the CSRF check was correct
466
-	 * @return bool true if CSRF check passed
467
-	 */
468
-	public function passesCSRFCheck() {
469
-		if($this->csrfTokenManager === null) {
470
-			return false;
471
-		}
472
-
473
-		if(!$this->passesStrictCookieCheck()) {
474
-			return false;
475
-		}
476
-
477
-		if (isset($this->items['get']['requesttoken'])) {
478
-			$token = $this->items['get']['requesttoken'];
479
-		} elseif (isset($this->items['post']['requesttoken'])) {
480
-			$token = $this->items['post']['requesttoken'];
481
-		} elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) {
482
-			$token = $this->items['server']['HTTP_REQUESTTOKEN'];
483
-		} else {
484
-			//no token found.
485
-			return false;
486
-		}
487
-		$token = new CsrfToken($token);
488
-
489
-		return $this->csrfTokenManager->isTokenValid($token);
490
-	}
491
-
492
-	/**
493
-	 * Whether the cookie checks are required
494
-	 *
495
-	 * @return bool
496
-	 */
497
-	private function cookieCheckRequired() {
498
-		if ($this->getHeader('OCS-APIREQUEST')) {
499
-			return false;
500
-		}
501
-		if($this->getCookie(session_name()) === null && $this->getCookie('nc_token') === null) {
502
-			return false;
503
-		}
504
-
505
-		return true;
506
-	}
507
-
508
-	/**
509
-	 * Wrapper around session_get_cookie_params
510
-	 *
511
-	 * @return array
512
-	 */
513
-	public function getCookieParams() {
514
-		return session_get_cookie_params();
515
-	}
516
-
517
-	/**
518
-	 * Appends the __Host- prefix to the cookie if applicable
519
-	 *
520
-	 * @param string $name
521
-	 * @return string
522
-	 */
523
-	protected function getProtectedCookieName($name) {
524
-		$cookieParams = $this->getCookieParams();
525
-		$prefix = '';
526
-		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
527
-			$prefix = '__Host-';
528
-		}
529
-
530
-		return $prefix.$name;
531
-	}
532
-
533
-	/**
534
-	 * Checks if the strict cookie has been sent with the request if the request
535
-	 * is including any cookies.
536
-	 *
537
-	 * @return bool
538
-	 * @since 9.1.0
539
-	 */
540
-	public function passesStrictCookieCheck() {
541
-		if(!$this->cookieCheckRequired()) {
542
-			return true;
543
-		}
544
-
545
-		$cookieName = $this->getProtectedCookieName('nc_sameSiteCookiestrict');
546
-		if($this->getCookie($cookieName) === 'true'
547
-			&& $this->passesLaxCookieCheck()) {
548
-			return true;
549
-		}
550
-		return false;
551
-	}
552
-
553
-	/**
554
-	 * Checks if the lax cookie has been sent with the request if the request
555
-	 * is including any cookies.
556
-	 *
557
-	 * @return bool
558
-	 * @since 9.1.0
559
-	 */
560
-	public function passesLaxCookieCheck() {
561
-		if(!$this->cookieCheckRequired()) {
562
-			return true;
563
-		}
564
-
565
-		$cookieName = $this->getProtectedCookieName('nc_sameSiteCookielax');
566
-		if($this->getCookie($cookieName) === 'true') {
567
-			return true;
568
-		}
569
-		return false;
570
-	}
571
-
572
-
573
-	/**
574
-	 * Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
575
-	 * If `mod_unique_id` is installed this value will be taken.
576
-	 * @return string
577
-	 */
578
-	public function getId() {
579
-		if(isset($this->server['UNIQUE_ID'])) {
580
-			return $this->server['UNIQUE_ID'];
581
-		}
582
-
583
-		if(empty($this->requestId)) {
584
-			$validChars = ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS;
585
-			$this->requestId = $this->secureRandom->generate(20, $validChars);
586
-		}
587
-
588
-		return $this->requestId;
589
-	}
590
-
591
-	/**
592
-	 * Returns the remote address, if the connection came from a trusted proxy
593
-	 * and `forwarded_for_headers` has been configured then the IP address
594
-	 * specified in this header will be returned instead.
595
-	 * Do always use this instead of $_SERVER['REMOTE_ADDR']
596
-	 * @return string IP address
597
-	 */
598
-	public function getRemoteAddress() {
599
-		$remoteAddress = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
600
-		$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
601
-
602
-		if(is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
603
-			$forwardedForHeaders = $this->config->getSystemValue('forwarded_for_headers', [
604
-				'HTTP_X_FORWARDED_FOR'
605
-				// only have one default, so we cannot ship an insecure product out of the box
606
-			]);
607
-
608
-			foreach($forwardedForHeaders as $header) {
609
-				if(isset($this->server[$header])) {
610
-					foreach(explode(',', $this->server[$header]) as $IP) {
611
-						$IP = trim($IP);
612
-						if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
613
-							return $IP;
614
-						}
615
-					}
616
-				}
617
-			}
618
-		}
619
-
620
-		return $remoteAddress;
621
-	}
622
-
623
-	/**
624
-	 * Check overwrite condition
625
-	 * @param string $type
626
-	 * @return bool
627
-	 */
628
-	private function isOverwriteCondition($type = '') {
629
-		$regex = '/' . $this->config->getSystemValue('overwritecondaddr', '')  . '/';
630
-		$remoteAddr = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
631
-		return $regex === '//' || preg_match($regex, $remoteAddr) === 1
632
-		|| $type !== 'protocol';
633
-	}
634
-
635
-	/**
636
-	 * Returns the server protocol. It respects one or more reverse proxies servers
637
-	 * and load balancers
638
-	 * @return string Server protocol (http or https)
639
-	 */
640
-	public function getServerProtocol() {
641
-		if($this->config->getSystemValue('overwriteprotocol') !== ''
642
-			&& $this->isOverwriteCondition('protocol')) {
643
-			return $this->config->getSystemValue('overwriteprotocol');
644
-		}
645
-
646
-		if (isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
647
-			if (strpos($this->server['HTTP_X_FORWARDED_PROTO'], ',') !== false) {
648
-				$parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
649
-				$proto = strtolower(trim($parts[0]));
650
-			} else {
651
-				$proto = strtolower($this->server['HTTP_X_FORWARDED_PROTO']);
652
-			}
653
-
654
-			// Verify that the protocol is always HTTP or HTTPS
655
-			// default to http if an invalid value is provided
656
-			return $proto === 'https' ? 'https' : 'http';
657
-		}
658
-
659
-		if (isset($this->server['HTTPS'])
660
-			&& $this->server['HTTPS'] !== null
661
-			&& $this->server['HTTPS'] !== 'off'
662
-			&& $this->server['HTTPS'] !== '') {
663
-			return 'https';
664
-		}
665
-
666
-		return 'http';
667
-	}
668
-
669
-	/**
670
-	 * Returns the used HTTP protocol.
671
-	 *
672
-	 * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
673
-	 */
674
-	public function getHttpProtocol() {
675
-		$claimedProtocol = strtoupper($this->server['SERVER_PROTOCOL']);
676
-
677
-		$validProtocols = [
678
-			'HTTP/1.0',
679
-			'HTTP/1.1',
680
-			'HTTP/2',
681
-		];
682
-
683
-		if(in_array($claimedProtocol, $validProtocols, true)) {
684
-			return $claimedProtocol;
685
-		}
686
-
687
-		return 'HTTP/1.1';
688
-	}
689
-
690
-	/**
691
-	 * Returns the request uri, even if the website uses one or more
692
-	 * reverse proxies
693
-	 * @return string
694
-	 */
695
-	public function getRequestUri() {
696
-		$uri = isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '';
697
-		if($this->config->getSystemValue('overwritewebroot') !== '' && $this->isOverwriteCondition()) {
698
-			$uri = $this->getScriptName() . substr($uri, strlen($this->server['SCRIPT_NAME']));
699
-		}
700
-		return $uri;
701
-	}
702
-
703
-	/**
704
-	 * Get raw PathInfo from request (not urldecoded)
705
-	 * @throws \Exception
706
-	 * @return string Path info
707
-	 */
708
-	public function getRawPathInfo() {
709
-		$requestUri = isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '';
710
-		// remove too many leading slashes - can be caused by reverse proxy configuration
711
-		if (strpos($requestUri, '/') === 0) {
712
-			$requestUri = '/' . ltrim($requestUri, '/');
713
-		}
714
-
715
-		$requestUri = preg_replace('%/{2,}%', '/', $requestUri);
716
-
717
-		// Remove the query string from REQUEST_URI
718
-		if ($pos = strpos($requestUri, '?')) {
719
-			$requestUri = substr($requestUri, 0, $pos);
720
-		}
721
-
722
-		$scriptName = $this->server['SCRIPT_NAME'];
723
-		$pathInfo = $requestUri;
724
-
725
-		// strip off the script name's dir and file name
726
-		// FIXME: Sabre does not really belong here
727
-		list($path, $name) = \Sabre\Uri\split($scriptName);
728
-		if (!empty($path)) {
729
-			if($path === $pathInfo || strpos($pathInfo, $path.'/') === 0) {
730
-				$pathInfo = substr($pathInfo, strlen($path));
731
-			} else {
732
-				throw new \Exception("The requested uri($requestUri) cannot be processed by the script '$scriptName')");
733
-			}
734
-		}
735
-		if (strpos($pathInfo, '/'.$name) === 0) {
736
-			$pathInfo = substr($pathInfo, strlen($name) + 1);
737
-		}
738
-		if (strpos($pathInfo, $name) === 0) {
739
-			$pathInfo = substr($pathInfo, strlen($name));
740
-		}
741
-		if($pathInfo === false || $pathInfo === '/'){
742
-			return '';
743
-		} else {
744
-			return $pathInfo;
745
-		}
746
-	}
747
-
748
-	/**
749
-	 * Get PathInfo from request
750
-	 * @throws \Exception
751
-	 * @return string|false Path info or false when not found
752
-	 */
753
-	public function getPathInfo() {
754
-		$pathInfo = $this->getRawPathInfo();
755
-		// following is taken from \Sabre\HTTP\URLUtil::decodePathSegment
756
-		$pathInfo = rawurldecode($pathInfo);
757
-		$encoding = mb_detect_encoding($pathInfo, ['UTF-8', 'ISO-8859-1']);
758
-
759
-		switch($encoding) {
760
-			case 'ISO-8859-1' :
761
-				$pathInfo = utf8_encode($pathInfo);
762
-		}
763
-		// end copy
764
-
765
-		return $pathInfo;
766
-	}
767
-
768
-	/**
769
-	 * Returns the script name, even if the website uses one or more
770
-	 * reverse proxies
771
-	 * @return string the script name
772
-	 */
773
-	public function getScriptName() {
774
-		$name = $this->server['SCRIPT_NAME'];
775
-		$overwriteWebRoot =  $this->config->getSystemValue('overwritewebroot');
776
-		if ($overwriteWebRoot !== '' && $this->isOverwriteCondition()) {
777
-			// FIXME: This code is untestable due to __DIR__, also that hardcoded path is really dangerous
778
-			$serverRoot = str_replace('\\', '/', substr(__DIR__, 0, -strlen('lib/private/appframework/http/')));
779
-			$suburi = str_replace('\\', '/', substr(realpath($this->server['SCRIPT_FILENAME']), strlen($serverRoot)));
780
-			$name = '/' . ltrim($overwriteWebRoot . $suburi, '/');
781
-		}
782
-		return $name;
783
-	}
784
-
785
-	/**
786
-	 * Checks whether the user agent matches a given regex
787
-	 * @param array $agent array of agent names
788
-	 * @return bool true if at least one of the given agent matches, false otherwise
789
-	 */
790
-	public function isUserAgent(array $agent) {
791
-		if (!isset($this->server['HTTP_USER_AGENT'])) {
792
-			return false;
793
-		}
794
-		foreach ($agent as $regex) {
795
-			if (preg_match($regex, $this->server['HTTP_USER_AGENT'])) {
796
-				return true;
797
-			}
798
-		}
799
-		return false;
800
-	}
801
-
802
-	/**
803
-	 * Returns the unverified server host from the headers without checking
804
-	 * whether it is a trusted domain
805
-	 * @return string Server host
806
-	 */
807
-	public function getInsecureServerHost() {
808
-		$host = 'localhost';
809
-		if (isset($this->server['HTTP_X_FORWARDED_HOST'])) {
810
-			if (strpos($this->server['HTTP_X_FORWARDED_HOST'], ',') !== false) {
811
-				$parts = explode(',', $this->server['HTTP_X_FORWARDED_HOST']);
812
-				$host = trim(current($parts));
813
-			} else {
814
-				$host = $this->server['HTTP_X_FORWARDED_HOST'];
815
-			}
816
-		} else {
817
-			if (isset($this->server['HTTP_HOST'])) {
818
-				$host = $this->server['HTTP_HOST'];
819
-			} else if (isset($this->server['SERVER_NAME'])) {
820
-				$host = $this->server['SERVER_NAME'];
821
-			}
822
-		}
823
-		return $host;
824
-	}
825
-
826
-
827
-	/**
828
-	 * Returns the server host from the headers, or the first configured
829
-	 * trusted domain if the host isn't in the trusted list
830
-	 * @return string Server host
831
-	 */
832
-	public function getServerHost() {
833
-		// overwritehost is always trusted
834
-		$host = $this->getOverwriteHost();
835
-		if ($host !== null) {
836
-			return $host;
837
-		}
838
-
839
-		// get the host from the headers
840
-		$host = $this->getInsecureServerHost();
841
-
842
-		// Verify that the host is a trusted domain if the trusted domains
843
-		// are defined
844
-		// If no trusted domain is provided the first trusted domain is returned
845
-		$trustedDomainHelper = new TrustedDomainHelper($this->config);
846
-		if ($trustedDomainHelper->isTrustedDomain($host)) {
847
-			return $host;
848
-		} else {
849
-			$trustedList = $this->config->getSystemValue('trusted_domains', []);
850
-			if(!empty($trustedList)) {
851
-				return $trustedList[0];
852
-			} else {
853
-				return '';
854
-			}
855
-		}
856
-	}
857
-
858
-	/**
859
-	 * Returns the overwritehost setting from the config if set and
860
-	 * if the overwrite condition is met
861
-	 * @return string|null overwritehost value or null if not defined or the defined condition
862
-	 * isn't met
863
-	 */
864
-	private function getOverwriteHost() {
865
-		if($this->config->getSystemValue('overwritehost') !== '' && $this->isOverwriteCondition()) {
866
-			return $this->config->getSystemValue('overwritehost');
867
-		}
868
-		return null;
869
-	}
61
+    const USER_AGENT_IE = '/(MSIE)|(Trident)/';
62
+    // Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
63
+    const USER_AGENT_MS_EDGE = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/';
64
+    // Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
65
+    const USER_AGENT_FIREFOX = '/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/[0-9.]+$/';
66
+    // Chrome User Agent from https://developer.chrome.com/multidevice/user-agent
67
+    const USER_AGENT_CHROME = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)( Ubuntu Chromium\/[0-9.]+|) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/';
68
+    // Safari User Agent from http://www.useragentstring.com/pages/Safari/
69
+    const USER_AGENT_SAFARI = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/[0-9.]+ Safari\/[0-9.A-Z]+$/';
70
+    // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
71
+    const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
72
+    const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
73
+    const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|::1)$/';
74
+
75
+    /**
76
+     * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_IOS instead
77
+     */
78
+    const USER_AGENT_OWNCLOUD_IOS = '/^Mozilla\/5\.0 \(iOS\) (ownCloud|Nextcloud)\-iOS.*$/';
79
+    /**
80
+     * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_ANDROID instead
81
+     */
82
+    const USER_AGENT_OWNCLOUD_ANDROID = '/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/';
83
+    /**
84
+     * @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_DESKTOP instead
85
+     */
86
+    const USER_AGENT_OWNCLOUD_DESKTOP = '/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/';
87
+
88
+    protected $inputStream;
89
+    protected $content;
90
+    protected $items = array();
91
+    protected $allowedKeys = array(
92
+        'get',
93
+        'post',
94
+        'files',
95
+        'server',
96
+        'env',
97
+        'cookies',
98
+        'urlParams',
99
+        'parameters',
100
+        'method',
101
+        'requesttoken',
102
+    );
103
+    /** @var ISecureRandom */
104
+    protected $secureRandom;
105
+    /** @var IConfig */
106
+    protected $config;
107
+    /** @var string */
108
+    protected $requestId = '';
109
+    /** @var ICrypto */
110
+    protected $crypto;
111
+    /** @var CsrfTokenManager|null */
112
+    protected $csrfTokenManager;
113
+
114
+    /** @var bool */
115
+    protected $contentDecoded = false;
116
+
117
+    /**
118
+     * @param array $vars An associative array with the following optional values:
119
+     *        - array 'urlParams' the parameters which were matched from the URL
120
+     *        - array 'get' the $_GET array
121
+     *        - array|string 'post' the $_POST array or JSON string
122
+     *        - array 'files' the $_FILES array
123
+     *        - array 'server' the $_SERVER array
124
+     *        - array 'env' the $_ENV array
125
+     *        - array 'cookies' the $_COOKIE array
126
+     *        - string 'method' the request method (GET, POST etc)
127
+     *        - string|false 'requesttoken' the requesttoken or false when not available
128
+     * @param ISecureRandom $secureRandom
129
+     * @param IConfig $config
130
+     * @param CsrfTokenManager|null $csrfTokenManager
131
+     * @param string $stream
132
+     * @see http://www.php.net/manual/en/reserved.variables.php
133
+     */
134
+    public function __construct(array $vars=array(),
135
+                                ISecureRandom $secureRandom = null,
136
+                                IConfig $config,
137
+                                CsrfTokenManager $csrfTokenManager = null,
138
+                                $stream = 'php://input') {
139
+        $this->inputStream = $stream;
140
+        $this->items['params'] = array();
141
+        $this->secureRandom = $secureRandom;
142
+        $this->config = $config;
143
+        $this->csrfTokenManager = $csrfTokenManager;
144
+
145
+        if(!array_key_exists('method', $vars)) {
146
+            $vars['method'] = 'GET';
147
+        }
148
+
149
+        foreach($this->allowedKeys as $name) {
150
+            $this->items[$name] = isset($vars[$name])
151
+                ? $vars[$name]
152
+                : array();
153
+        }
154
+
155
+        $this->items['parameters'] = array_merge(
156
+            $this->items['get'],
157
+            $this->items['post'],
158
+            $this->items['urlParams'],
159
+            $this->items['params']
160
+        );
161
+
162
+    }
163
+    /**
164
+     * @param array $parameters
165
+     */
166
+    public function setUrlParameters(array $parameters) {
167
+        $this->items['urlParams'] = $parameters;
168
+        $this->items['parameters'] = array_merge(
169
+            $this->items['parameters'],
170
+            $this->items['urlParams']
171
+        );
172
+    }
173
+
174
+    /**
175
+     * Countable method
176
+     * @return int
177
+     */
178
+    public function count() {
179
+        return count(array_keys($this->items['parameters']));
180
+    }
181
+
182
+    /**
183
+     * ArrayAccess methods
184
+     *
185
+     * Gives access to the combined GET, POST and urlParams arrays
186
+     *
187
+     * Examples:
188
+     *
189
+     * $var = $request['myvar'];
190
+     *
191
+     * or
192
+     *
193
+     * if(!isset($request['myvar']) {
194
+     * 	// Do something
195
+     * }
196
+     *
197
+     * $request['myvar'] = 'something'; // This throws an exception.
198
+     *
199
+     * @param string $offset The key to lookup
200
+     * @return boolean
201
+     */
202
+    public function offsetExists($offset) {
203
+        return isset($this->items['parameters'][$offset]);
204
+    }
205
+
206
+    /**
207
+     * @see offsetExists
208
+     */
209
+    public function offsetGet($offset) {
210
+        return isset($this->items['parameters'][$offset])
211
+            ? $this->items['parameters'][$offset]
212
+            : null;
213
+    }
214
+
215
+    /**
216
+     * @see offsetExists
217
+     */
218
+    public function offsetSet($offset, $value) {
219
+        throw new \RuntimeException('You cannot change the contents of the request object');
220
+    }
221
+
222
+    /**
223
+     * @see offsetExists
224
+     */
225
+    public function offsetUnset($offset) {
226
+        throw new \RuntimeException('You cannot change the contents of the request object');
227
+    }
228
+
229
+    /**
230
+     * Magic property accessors
231
+     * @param string $name
232
+     * @param mixed $value
233
+     */
234
+    public function __set($name, $value) {
235
+        throw new \RuntimeException('You cannot change the contents of the request object');
236
+    }
237
+
238
+    /**
239
+     * Access request variables by method and name.
240
+     * Examples:
241
+     *
242
+     * $request->post['myvar']; // Only look for POST variables
243
+     * $request->myvar; or $request->{'myvar'}; or $request->{$myvar}
244
+     * Looks in the combined GET, POST and urlParams array.
245
+     *
246
+     * If you access e.g. ->post but the current HTTP request method
247
+     * is GET a \LogicException will be thrown.
248
+     *
249
+     * @param string $name The key to look for.
250
+     * @throws \LogicException
251
+     * @return mixed|null
252
+     */
253
+    public function __get($name) {
254
+        switch($name) {
255
+            case 'put':
256
+            case 'patch':
257
+            case 'get':
258
+            case 'post':
259
+                if($this->method !== strtoupper($name)) {
260
+                    throw new \LogicException(sprintf('%s cannot be accessed in a %s request.', $name, $this->method));
261
+                }
262
+                return $this->getContent();
263
+            case 'files':
264
+            case 'server':
265
+            case 'env':
266
+            case 'cookies':
267
+            case 'urlParams':
268
+            case 'method':
269
+                return isset($this->items[$name])
270
+                    ? $this->items[$name]
271
+                    : null;
272
+            case 'parameters':
273
+            case 'params':
274
+                return $this->getContent();
275
+            default;
276
+                return isset($this[$name])
277
+                    ? $this[$name]
278
+                    : null;
279
+        }
280
+    }
281
+
282
+    /**
283
+     * @param string $name
284
+     * @return bool
285
+     */
286
+    public function __isset($name) {
287
+        if (in_array($name, $this->allowedKeys, true)) {
288
+            return true;
289
+        }
290
+        return isset($this->items['parameters'][$name]);
291
+    }
292
+
293
+    /**
294
+     * @param string $id
295
+     */
296
+    public function __unset($id) {
297
+        throw new \RuntimeException('You cannot change the contents of the request object');
298
+    }
299
+
300
+    /**
301
+     * Returns the value for a specific http header.
302
+     *
303
+     * This method returns null if the header did not exist.
304
+     *
305
+     * @param string $name
306
+     * @return string
307
+     */
308
+    public function getHeader($name) {
309
+
310
+        $name = strtoupper(str_replace(array('-'),array('_'),$name));
311
+        if (isset($this->server['HTTP_' . $name])) {
312
+            return $this->server['HTTP_' . $name];
313
+        }
314
+
315
+        // There's a few headers that seem to end up in the top-level
316
+        // server array.
317
+        switch($name) {
318
+            case 'CONTENT_TYPE' :
319
+            case 'CONTENT_LENGTH' :
320
+                if (isset($this->server[$name])) {
321
+                    return $this->server[$name];
322
+                }
323
+                break;
324
+
325
+        }
326
+
327
+        return '';
328
+    }
329
+
330
+    /**
331
+     * Lets you access post and get parameters by the index
332
+     * In case of json requests the encoded json body is accessed
333
+     *
334
+     * @param string $key the key which you want to access in the URL Parameter
335
+     *                     placeholder, $_POST or $_GET array.
336
+     *                     The priority how they're returned is the following:
337
+     *                     1. URL parameters
338
+     *                     2. POST parameters
339
+     *                     3. GET parameters
340
+     * @param mixed $default If the key is not found, this value will be returned
341
+     * @return mixed the content of the array
342
+     */
343
+    public function getParam($key, $default = null) {
344
+        return isset($this->parameters[$key])
345
+            ? $this->parameters[$key]
346
+            : $default;
347
+    }
348
+
349
+    /**
350
+     * Returns all params that were received, be it from the request
351
+     * (as GET or POST) or throuh the URL by the route
352
+     * @return array the array with all parameters
353
+     */
354
+    public function getParams() {
355
+        return $this->parameters;
356
+    }
357
+
358
+    /**
359
+     * Returns the method of the request
360
+     * @return string the method of the request (POST, GET, etc)
361
+     */
362
+    public function getMethod() {
363
+        return $this->method;
364
+    }
365
+
366
+    /**
367
+     * Shortcut for accessing an uploaded file through the $_FILES array
368
+     * @param string $key the key that will be taken from the $_FILES array
369
+     * @return array the file in the $_FILES element
370
+     */
371
+    public function getUploadedFile($key) {
372
+        return isset($this->files[$key]) ? $this->files[$key] : null;
373
+    }
374
+
375
+    /**
376
+     * Shortcut for getting env variables
377
+     * @param string $key the key that will be taken from the $_ENV array
378
+     * @return array the value in the $_ENV element
379
+     */
380
+    public function getEnv($key) {
381
+        return isset($this->env[$key]) ? $this->env[$key] : null;
382
+    }
383
+
384
+    /**
385
+     * Shortcut for getting cookie variables
386
+     * @param string $key the key that will be taken from the $_COOKIE array
387
+     * @return string the value in the $_COOKIE element
388
+     */
389
+    public function getCookie($key) {
390
+        return isset($this->cookies[$key]) ? $this->cookies[$key] : null;
391
+    }
392
+
393
+    /**
394
+     * Returns the request body content.
395
+     *
396
+     * If the HTTP request method is PUT and the body
397
+     * not application/x-www-form-urlencoded or application/json a stream
398
+     * resource is returned, otherwise an array.
399
+     *
400
+     * @return array|string|resource The request body content or a resource to read the body stream.
401
+     *
402
+     * @throws \LogicException
403
+     */
404
+    protected function getContent() {
405
+        // If the content can't be parsed into an array then return a stream resource.
406
+        if ($this->method === 'PUT'
407
+            && $this->getHeader('Content-Length') !== '0'
408
+            && $this->getHeader('Content-Length') !== ''
409
+            && strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') === false
410
+            && strpos($this->getHeader('Content-Type'), 'application/json') === false
411
+        ) {
412
+            if ($this->content === false) {
413
+                throw new \LogicException(
414
+                    '"put" can only be accessed once if not '
415
+                    . 'application/x-www-form-urlencoded or application/json.'
416
+                );
417
+            }
418
+            $this->content = false;
419
+            return fopen($this->inputStream, 'rb');
420
+        } else {
421
+            $this->decodeContent();
422
+            return $this->items['parameters'];
423
+        }
424
+    }
425
+
426
+    /**
427
+     * Attempt to decode the content and populate parameters
428
+     */
429
+    protected function decodeContent() {
430
+        if ($this->contentDecoded) {
431
+            return;
432
+        }
433
+        $params = [];
434
+
435
+        // 'application/json' must be decoded manually.
436
+        if (strpos($this->getHeader('Content-Type'), 'application/json') !== false) {
437
+            $params = json_decode(file_get_contents($this->inputStream), true);
438
+            if($params !== null && count($params) > 0) {
439
+                $this->items['params'] = $params;
440
+                if($this->method === 'POST') {
441
+                    $this->items['post'] = $params;
442
+                }
443
+            }
444
+
445
+        // Handle application/x-www-form-urlencoded for methods other than GET
446
+        // or post correctly
447
+        } elseif($this->method !== 'GET'
448
+                && $this->method !== 'POST'
449
+                && strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') !== false) {
450
+
451
+            parse_str(file_get_contents($this->inputStream), $params);
452
+            if(is_array($params)) {
453
+                $this->items['params'] = $params;
454
+            }
455
+        }
456
+
457
+        if (is_array($params)) {
458
+            $this->items['parameters'] = array_merge($this->items['parameters'], $params);
459
+        }
460
+        $this->contentDecoded = true;
461
+    }
462
+
463
+
464
+    /**
465
+     * Checks if the CSRF check was correct
466
+     * @return bool true if CSRF check passed
467
+     */
468
+    public function passesCSRFCheck() {
469
+        if($this->csrfTokenManager === null) {
470
+            return false;
471
+        }
472
+
473
+        if(!$this->passesStrictCookieCheck()) {
474
+            return false;
475
+        }
476
+
477
+        if (isset($this->items['get']['requesttoken'])) {
478
+            $token = $this->items['get']['requesttoken'];
479
+        } elseif (isset($this->items['post']['requesttoken'])) {
480
+            $token = $this->items['post']['requesttoken'];
481
+        } elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) {
482
+            $token = $this->items['server']['HTTP_REQUESTTOKEN'];
483
+        } else {
484
+            //no token found.
485
+            return false;
486
+        }
487
+        $token = new CsrfToken($token);
488
+
489
+        return $this->csrfTokenManager->isTokenValid($token);
490
+    }
491
+
492
+    /**
493
+     * Whether the cookie checks are required
494
+     *
495
+     * @return bool
496
+     */
497
+    private function cookieCheckRequired() {
498
+        if ($this->getHeader('OCS-APIREQUEST')) {
499
+            return false;
500
+        }
501
+        if($this->getCookie(session_name()) === null && $this->getCookie('nc_token') === null) {
502
+            return false;
503
+        }
504
+
505
+        return true;
506
+    }
507
+
508
+    /**
509
+     * Wrapper around session_get_cookie_params
510
+     *
511
+     * @return array
512
+     */
513
+    public function getCookieParams() {
514
+        return session_get_cookie_params();
515
+    }
516
+
517
+    /**
518
+     * Appends the __Host- prefix to the cookie if applicable
519
+     *
520
+     * @param string $name
521
+     * @return string
522
+     */
523
+    protected function getProtectedCookieName($name) {
524
+        $cookieParams = $this->getCookieParams();
525
+        $prefix = '';
526
+        if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
527
+            $prefix = '__Host-';
528
+        }
529
+
530
+        return $prefix.$name;
531
+    }
532
+
533
+    /**
534
+     * Checks if the strict cookie has been sent with the request if the request
535
+     * is including any cookies.
536
+     *
537
+     * @return bool
538
+     * @since 9.1.0
539
+     */
540
+    public function passesStrictCookieCheck() {
541
+        if(!$this->cookieCheckRequired()) {
542
+            return true;
543
+        }
544
+
545
+        $cookieName = $this->getProtectedCookieName('nc_sameSiteCookiestrict');
546
+        if($this->getCookie($cookieName) === 'true'
547
+            && $this->passesLaxCookieCheck()) {
548
+            return true;
549
+        }
550
+        return false;
551
+    }
552
+
553
+    /**
554
+     * Checks if the lax cookie has been sent with the request if the request
555
+     * is including any cookies.
556
+     *
557
+     * @return bool
558
+     * @since 9.1.0
559
+     */
560
+    public function passesLaxCookieCheck() {
561
+        if(!$this->cookieCheckRequired()) {
562
+            return true;
563
+        }
564
+
565
+        $cookieName = $this->getProtectedCookieName('nc_sameSiteCookielax');
566
+        if($this->getCookie($cookieName) === 'true') {
567
+            return true;
568
+        }
569
+        return false;
570
+    }
571
+
572
+
573
+    /**
574
+     * Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
575
+     * If `mod_unique_id` is installed this value will be taken.
576
+     * @return string
577
+     */
578
+    public function getId() {
579
+        if(isset($this->server['UNIQUE_ID'])) {
580
+            return $this->server['UNIQUE_ID'];
581
+        }
582
+
583
+        if(empty($this->requestId)) {
584
+            $validChars = ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS;
585
+            $this->requestId = $this->secureRandom->generate(20, $validChars);
586
+        }
587
+
588
+        return $this->requestId;
589
+    }
590
+
591
+    /**
592
+     * Returns the remote address, if the connection came from a trusted proxy
593
+     * and `forwarded_for_headers` has been configured then the IP address
594
+     * specified in this header will be returned instead.
595
+     * Do always use this instead of $_SERVER['REMOTE_ADDR']
596
+     * @return string IP address
597
+     */
598
+    public function getRemoteAddress() {
599
+        $remoteAddress = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
600
+        $trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
601
+
602
+        if(is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
603
+            $forwardedForHeaders = $this->config->getSystemValue('forwarded_for_headers', [
604
+                'HTTP_X_FORWARDED_FOR'
605
+                // only have one default, so we cannot ship an insecure product out of the box
606
+            ]);
607
+
608
+            foreach($forwardedForHeaders as $header) {
609
+                if(isset($this->server[$header])) {
610
+                    foreach(explode(',', $this->server[$header]) as $IP) {
611
+                        $IP = trim($IP);
612
+                        if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
613
+                            return $IP;
614
+                        }
615
+                    }
616
+                }
617
+            }
618
+        }
619
+
620
+        return $remoteAddress;
621
+    }
622
+
623
+    /**
624
+     * Check overwrite condition
625
+     * @param string $type
626
+     * @return bool
627
+     */
628
+    private function isOverwriteCondition($type = '') {
629
+        $regex = '/' . $this->config->getSystemValue('overwritecondaddr', '')  . '/';
630
+        $remoteAddr = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
631
+        return $regex === '//' || preg_match($regex, $remoteAddr) === 1
632
+        || $type !== 'protocol';
633
+    }
634
+
635
+    /**
636
+     * Returns the server protocol. It respects one or more reverse proxies servers
637
+     * and load balancers
638
+     * @return string Server protocol (http or https)
639
+     */
640
+    public function getServerProtocol() {
641
+        if($this->config->getSystemValue('overwriteprotocol') !== ''
642
+            && $this->isOverwriteCondition('protocol')) {
643
+            return $this->config->getSystemValue('overwriteprotocol');
644
+        }
645
+
646
+        if (isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
647
+            if (strpos($this->server['HTTP_X_FORWARDED_PROTO'], ',') !== false) {
648
+                $parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
649
+                $proto = strtolower(trim($parts[0]));
650
+            } else {
651
+                $proto = strtolower($this->server['HTTP_X_FORWARDED_PROTO']);
652
+            }
653
+
654
+            // Verify that the protocol is always HTTP or HTTPS
655
+            // default to http if an invalid value is provided
656
+            return $proto === 'https' ? 'https' : 'http';
657
+        }
658
+
659
+        if (isset($this->server['HTTPS'])
660
+            && $this->server['HTTPS'] !== null
661
+            && $this->server['HTTPS'] !== 'off'
662
+            && $this->server['HTTPS'] !== '') {
663
+            return 'https';
664
+        }
665
+
666
+        return 'http';
667
+    }
668
+
669
+    /**
670
+     * Returns the used HTTP protocol.
671
+     *
672
+     * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
673
+     */
674
+    public function getHttpProtocol() {
675
+        $claimedProtocol = strtoupper($this->server['SERVER_PROTOCOL']);
676
+
677
+        $validProtocols = [
678
+            'HTTP/1.0',
679
+            'HTTP/1.1',
680
+            'HTTP/2',
681
+        ];
682
+
683
+        if(in_array($claimedProtocol, $validProtocols, true)) {
684
+            return $claimedProtocol;
685
+        }
686
+
687
+        return 'HTTP/1.1';
688
+    }
689
+
690
+    /**
691
+     * Returns the request uri, even if the website uses one or more
692
+     * reverse proxies
693
+     * @return string
694
+     */
695
+    public function getRequestUri() {
696
+        $uri = isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '';
697
+        if($this->config->getSystemValue('overwritewebroot') !== '' && $this->isOverwriteCondition()) {
698
+            $uri = $this->getScriptName() . substr($uri, strlen($this->server['SCRIPT_NAME']));
699
+        }
700
+        return $uri;
701
+    }
702
+
703
+    /**
704
+     * Get raw PathInfo from request (not urldecoded)
705
+     * @throws \Exception
706
+     * @return string Path info
707
+     */
708
+    public function getRawPathInfo() {
709
+        $requestUri = isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '';
710
+        // remove too many leading slashes - can be caused by reverse proxy configuration
711
+        if (strpos($requestUri, '/') === 0) {
712
+            $requestUri = '/' . ltrim($requestUri, '/');
713
+        }
714
+
715
+        $requestUri = preg_replace('%/{2,}%', '/', $requestUri);
716
+
717
+        // Remove the query string from REQUEST_URI
718
+        if ($pos = strpos($requestUri, '?')) {
719
+            $requestUri = substr($requestUri, 0, $pos);
720
+        }
721
+
722
+        $scriptName = $this->server['SCRIPT_NAME'];
723
+        $pathInfo = $requestUri;
724
+
725
+        // strip off the script name's dir and file name
726
+        // FIXME: Sabre does not really belong here
727
+        list($path, $name) = \Sabre\Uri\split($scriptName);
728
+        if (!empty($path)) {
729
+            if($path === $pathInfo || strpos($pathInfo, $path.'/') === 0) {
730
+                $pathInfo = substr($pathInfo, strlen($path));
731
+            } else {
732
+                throw new \Exception("The requested uri($requestUri) cannot be processed by the script '$scriptName')");
733
+            }
734
+        }
735
+        if (strpos($pathInfo, '/'.$name) === 0) {
736
+            $pathInfo = substr($pathInfo, strlen($name) + 1);
737
+        }
738
+        if (strpos($pathInfo, $name) === 0) {
739
+            $pathInfo = substr($pathInfo, strlen($name));
740
+        }
741
+        if($pathInfo === false || $pathInfo === '/'){
742
+            return '';
743
+        } else {
744
+            return $pathInfo;
745
+        }
746
+    }
747
+
748
+    /**
749
+     * Get PathInfo from request
750
+     * @throws \Exception
751
+     * @return string|false Path info or false when not found
752
+     */
753
+    public function getPathInfo() {
754
+        $pathInfo = $this->getRawPathInfo();
755
+        // following is taken from \Sabre\HTTP\URLUtil::decodePathSegment
756
+        $pathInfo = rawurldecode($pathInfo);
757
+        $encoding = mb_detect_encoding($pathInfo, ['UTF-8', 'ISO-8859-1']);
758
+
759
+        switch($encoding) {
760
+            case 'ISO-8859-1' :
761
+                $pathInfo = utf8_encode($pathInfo);
762
+        }
763
+        // end copy
764
+
765
+        return $pathInfo;
766
+    }
767
+
768
+    /**
769
+     * Returns the script name, even if the website uses one or more
770
+     * reverse proxies
771
+     * @return string the script name
772
+     */
773
+    public function getScriptName() {
774
+        $name = $this->server['SCRIPT_NAME'];
775
+        $overwriteWebRoot =  $this->config->getSystemValue('overwritewebroot');
776
+        if ($overwriteWebRoot !== '' && $this->isOverwriteCondition()) {
777
+            // FIXME: This code is untestable due to __DIR__, also that hardcoded path is really dangerous
778
+            $serverRoot = str_replace('\\', '/', substr(__DIR__, 0, -strlen('lib/private/appframework/http/')));
779
+            $suburi = str_replace('\\', '/', substr(realpath($this->server['SCRIPT_FILENAME']), strlen($serverRoot)));
780
+            $name = '/' . ltrim($overwriteWebRoot . $suburi, '/');
781
+        }
782
+        return $name;
783
+    }
784
+
785
+    /**
786
+     * Checks whether the user agent matches a given regex
787
+     * @param array $agent array of agent names
788
+     * @return bool true if at least one of the given agent matches, false otherwise
789
+     */
790
+    public function isUserAgent(array $agent) {
791
+        if (!isset($this->server['HTTP_USER_AGENT'])) {
792
+            return false;
793
+        }
794
+        foreach ($agent as $regex) {
795
+            if (preg_match($regex, $this->server['HTTP_USER_AGENT'])) {
796
+                return true;
797
+            }
798
+        }
799
+        return false;
800
+    }
801
+
802
+    /**
803
+     * Returns the unverified server host from the headers without checking
804
+     * whether it is a trusted domain
805
+     * @return string Server host
806
+     */
807
+    public function getInsecureServerHost() {
808
+        $host = 'localhost';
809
+        if (isset($this->server['HTTP_X_FORWARDED_HOST'])) {
810
+            if (strpos($this->server['HTTP_X_FORWARDED_HOST'], ',') !== false) {
811
+                $parts = explode(',', $this->server['HTTP_X_FORWARDED_HOST']);
812
+                $host = trim(current($parts));
813
+            } else {
814
+                $host = $this->server['HTTP_X_FORWARDED_HOST'];
815
+            }
816
+        } else {
817
+            if (isset($this->server['HTTP_HOST'])) {
818
+                $host = $this->server['HTTP_HOST'];
819
+            } else if (isset($this->server['SERVER_NAME'])) {
820
+                $host = $this->server['SERVER_NAME'];
821
+            }
822
+        }
823
+        return $host;
824
+    }
825
+
826
+
827
+    /**
828
+     * Returns the server host from the headers, or the first configured
829
+     * trusted domain if the host isn't in the trusted list
830
+     * @return string Server host
831
+     */
832
+    public function getServerHost() {
833
+        // overwritehost is always trusted
834
+        $host = $this->getOverwriteHost();
835
+        if ($host !== null) {
836
+            return $host;
837
+        }
838
+
839
+        // get the host from the headers
840
+        $host = $this->getInsecureServerHost();
841
+
842
+        // Verify that the host is a trusted domain if the trusted domains
843
+        // are defined
844
+        // If no trusted domain is provided the first trusted domain is returned
845
+        $trustedDomainHelper = new TrustedDomainHelper($this->config);
846
+        if ($trustedDomainHelper->isTrustedDomain($host)) {
847
+            return $host;
848
+        } else {
849
+            $trustedList = $this->config->getSystemValue('trusted_domains', []);
850
+            if(!empty($trustedList)) {
851
+                return $trustedList[0];
852
+            } else {
853
+                return '';
854
+            }
855
+        }
856
+    }
857
+
858
+    /**
859
+     * Returns the overwritehost setting from the config if set and
860
+     * if the overwrite condition is met
861
+     * @return string|null overwritehost value or null if not defined or the defined condition
862
+     * isn't met
863
+     */
864
+    private function getOverwriteHost() {
865
+        if($this->config->getSystemValue('overwritehost') !== '' && $this->isOverwriteCondition()) {
866
+            return $this->config->getSystemValue('overwritehost');
867
+        }
868
+        return null;
869
+    }
870 870
 
871 871
 }
Please login to merge, or discard this patch.
lib/private/Log/File.php 1 patch
Indentation   +156 added lines, -156 removed lines patch added patch discarded remove patch
@@ -44,166 +44,166 @@
 block discarded – undo
44 44
  */
45 45
 
46 46
 class File {
47
-	static protected $logFile;
47
+    static protected $logFile;
48 48
 
49
-	/**
50
-	 * Init class data
51
-	 */
52
-	public static function init() {
53
-		$systemConfig = \OC::$server->getSystemConfig();
54
-		$defaultLogFile = $systemConfig->getValue("datadirectory", \OC::$SERVERROOT.'/data').'/nextcloud.log';
55
-		self::$logFile = $systemConfig->getValue("logfile", $defaultLogFile);
49
+    /**
50
+     * Init class data
51
+     */
52
+    public static function init() {
53
+        $systemConfig = \OC::$server->getSystemConfig();
54
+        $defaultLogFile = $systemConfig->getValue("datadirectory", \OC::$SERVERROOT.'/data').'/nextcloud.log';
55
+        self::$logFile = $systemConfig->getValue("logfile", $defaultLogFile);
56 56
 
57
-		/**
58
-		 * Fall back to default log file if specified logfile does not exist
59
-		 * and can not be created.
60
-		 */
61
-		if (!file_exists(self::$logFile)) {
62
-			if(!is_writable(dirname(self::$logFile))) {
63
-				self::$logFile = $defaultLogFile;
64
-			} else {
65
-				if(!touch(self::$logFile)) {
66
-					self::$logFile = $defaultLogFile;
67
-				}
68
-			}
69
-		}
70
-	}
57
+        /**
58
+         * Fall back to default log file if specified logfile does not exist
59
+         * and can not be created.
60
+         */
61
+        if (!file_exists(self::$logFile)) {
62
+            if(!is_writable(dirname(self::$logFile))) {
63
+                self::$logFile = $defaultLogFile;
64
+            } else {
65
+                if(!touch(self::$logFile)) {
66
+                    self::$logFile = $defaultLogFile;
67
+                }
68
+            }
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * write a message in the log
74
-	 * @param string $app
75
-	 * @param string $message
76
-	 * @param int $level
77
-	 */
78
-	public static function write($app, $message, $level) {
79
-		$config = \OC::$server->getSystemConfig();
72
+    /**
73
+     * write a message in the log
74
+     * @param string $app
75
+     * @param string $message
76
+     * @param int $level
77
+     */
78
+    public static function write($app, $message, $level) {
79
+        $config = \OC::$server->getSystemConfig();
80 80
 
81
-		// default to ISO8601
82
-		$format = $config->getValue('logdateformat', \DateTime::ATOM);
83
-		$logTimeZone = $config->getValue('logtimezone', 'UTC');
84
-		try {
85
-			$timezone = new \DateTimeZone($logTimeZone);
86
-		} catch (\Exception $e) {
87
-			$timezone = new \DateTimeZone('UTC');
88
-		}
89
-		$time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
90
-		if ($time === false) {
91
-			$time = new \DateTime(null, $timezone);
92
-		} else {
93
-			// apply timezone if $time is created from UNIX timestamp
94
-			$time->setTimezone($timezone);
95
-		}
96
-		$request = \OC::$server->getRequest();
97
-		$reqId = $request->getId();
98
-		$remoteAddr = $request->getRemoteAddress();
99
-		// remove username/passwords from URLs before writing the to the log file
100
-		$time = $time->format($format);
101
-		$url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
102
-		$method = is_string($request->getMethod()) ? $request->getMethod() : '--';
103
-		if($config->getValue('installed', false)) {
104
-			$user = (\OC_User::getUser()) ? \OC_User::getUser() : '--';
105
-		} else {
106
-			$user = '--';
107
-		}
108
-		$userAgent = $request->getHeader('User-Agent');
109
-		if ($userAgent === '') {
110
-			$userAgent = '--';
111
-		}
112
-		$version = $config->getValue('version', '');
113
-		$entry = compact(
114
-			'reqId',
115
-			'level',
116
-			'time',
117
-			'remoteAddr',
118
-			'user',
119
-			'app',
120
-			'method',
121
-			'url',
122
-			'message',
123
-			'userAgent',
124
-			'version'
125
-		);
126
-		// PHP's json_encode only accept proper UTF-8 strings, loop over all
127
-		// elements to ensure that they are properly UTF-8 compliant or convert
128
-		// them manually.
129
-		foreach($entry as $key => $value) {
130
-			if(is_string($value)) {
131
-				$testEncode = json_encode($value);
132
-				if($testEncode === false) {
133
-					$entry[$key] = utf8_encode($value);
134
-				}
135
-			}
136
-		}
137
-		$entry = json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
138
-		$handle = @fopen(self::$logFile, 'a');
139
-		if ((fileperms(self::$logFile) & 0777) != 0640) {
140
-			@chmod(self::$logFile, 0640);
141
-		}
142
-		if ($handle) {
143
-			fwrite($handle, $entry."\n");
144
-			fclose($handle);
145
-		} else {
146
-			// Fall back to error_log
147
-			error_log($entry);
148
-		}
149
-		if (php_sapi_name() === 'cli-server') {
150
-			error_log($message, 4);
151
-		}
152
-	}
81
+        // default to ISO8601
82
+        $format = $config->getValue('logdateformat', \DateTime::ATOM);
83
+        $logTimeZone = $config->getValue('logtimezone', 'UTC');
84
+        try {
85
+            $timezone = new \DateTimeZone($logTimeZone);
86
+        } catch (\Exception $e) {
87
+            $timezone = new \DateTimeZone('UTC');
88
+        }
89
+        $time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
90
+        if ($time === false) {
91
+            $time = new \DateTime(null, $timezone);
92
+        } else {
93
+            // apply timezone if $time is created from UNIX timestamp
94
+            $time->setTimezone($timezone);
95
+        }
96
+        $request = \OC::$server->getRequest();
97
+        $reqId = $request->getId();
98
+        $remoteAddr = $request->getRemoteAddress();
99
+        // remove username/passwords from URLs before writing the to the log file
100
+        $time = $time->format($format);
101
+        $url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
102
+        $method = is_string($request->getMethod()) ? $request->getMethod() : '--';
103
+        if($config->getValue('installed', false)) {
104
+            $user = (\OC_User::getUser()) ? \OC_User::getUser() : '--';
105
+        } else {
106
+            $user = '--';
107
+        }
108
+        $userAgent = $request->getHeader('User-Agent');
109
+        if ($userAgent === '') {
110
+            $userAgent = '--';
111
+        }
112
+        $version = $config->getValue('version', '');
113
+        $entry = compact(
114
+            'reqId',
115
+            'level',
116
+            'time',
117
+            'remoteAddr',
118
+            'user',
119
+            'app',
120
+            'method',
121
+            'url',
122
+            'message',
123
+            'userAgent',
124
+            'version'
125
+        );
126
+        // PHP's json_encode only accept proper UTF-8 strings, loop over all
127
+        // elements to ensure that they are properly UTF-8 compliant or convert
128
+        // them manually.
129
+        foreach($entry as $key => $value) {
130
+            if(is_string($value)) {
131
+                $testEncode = json_encode($value);
132
+                if($testEncode === false) {
133
+                    $entry[$key] = utf8_encode($value);
134
+                }
135
+            }
136
+        }
137
+        $entry = json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
138
+        $handle = @fopen(self::$logFile, 'a');
139
+        if ((fileperms(self::$logFile) & 0777) != 0640) {
140
+            @chmod(self::$logFile, 0640);
141
+        }
142
+        if ($handle) {
143
+            fwrite($handle, $entry."\n");
144
+            fclose($handle);
145
+        } else {
146
+            // Fall back to error_log
147
+            error_log($entry);
148
+        }
149
+        if (php_sapi_name() === 'cli-server') {
150
+            error_log($message, 4);
151
+        }
152
+    }
153 153
 
154
-	/**
155
-	 * get entries from the log in reverse chronological order
156
-	 * @param int $limit
157
-	 * @param int $offset
158
-	 * @return array
159
-	 */
160
-	public static function getEntries($limit=50, $offset=0) {
161
-		self::init();
162
-		$minLevel = \OC::$server->getSystemConfig()->getValue("loglevel", \OCP\Util::WARN);
163
-		$entries = array();
164
-		$handle = @fopen(self::$logFile, 'rb');
165
-		if ($handle) {
166
-			fseek($handle, 0, SEEK_END);
167
-			$pos = ftell($handle);
168
-			$line = '';
169
-			$entriesCount = 0;
170
-			$lines = 0;
171
-			// Loop through each character of the file looking for new lines
172
-			while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
173
-				fseek($handle, $pos);
174
-				$ch = fgetc($handle);
175
-				if ($ch == "\n" || $pos == 0) {
176
-					if ($line != '') {
177
-						// Add the first character if at the start of the file,
178
-						// because it doesn't hit the else in the loop
179
-						if ($pos == 0) {
180
-							$line = $ch.$line;
181
-						}
182
-						$entry = json_decode($line);
183
-						// Add the line as an entry if it is passed the offset and is equal or above the log level
184
-						if ($entry->level >= $minLevel) {
185
-							$lines++;
186
-							if ($lines > $offset) {
187
-								$entries[] = $entry;
188
-								$entriesCount++;
189
-							}
190
-						}
191
-						$line = '';
192
-					}
193
-				} else {
194
-					$line = $ch.$line;
195
-				}
196
-				$pos--;
197
-			}
198
-			fclose($handle);
199
-		}
200
-		return $entries;
201
-	}
154
+    /**
155
+     * get entries from the log in reverse chronological order
156
+     * @param int $limit
157
+     * @param int $offset
158
+     * @return array
159
+     */
160
+    public static function getEntries($limit=50, $offset=0) {
161
+        self::init();
162
+        $minLevel = \OC::$server->getSystemConfig()->getValue("loglevel", \OCP\Util::WARN);
163
+        $entries = array();
164
+        $handle = @fopen(self::$logFile, 'rb');
165
+        if ($handle) {
166
+            fseek($handle, 0, SEEK_END);
167
+            $pos = ftell($handle);
168
+            $line = '';
169
+            $entriesCount = 0;
170
+            $lines = 0;
171
+            // Loop through each character of the file looking for new lines
172
+            while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
173
+                fseek($handle, $pos);
174
+                $ch = fgetc($handle);
175
+                if ($ch == "\n" || $pos == 0) {
176
+                    if ($line != '') {
177
+                        // Add the first character if at the start of the file,
178
+                        // because it doesn't hit the else in the loop
179
+                        if ($pos == 0) {
180
+                            $line = $ch.$line;
181
+                        }
182
+                        $entry = json_decode($line);
183
+                        // Add the line as an entry if it is passed the offset and is equal or above the log level
184
+                        if ($entry->level >= $minLevel) {
185
+                            $lines++;
186
+                            if ($lines > $offset) {
187
+                                $entries[] = $entry;
188
+                                $entriesCount++;
189
+                            }
190
+                        }
191
+                        $line = '';
192
+                    }
193
+                } else {
194
+                    $line = $ch.$line;
195
+                }
196
+                $pos--;
197
+            }
198
+            fclose($handle);
199
+        }
200
+        return $entries;
201
+    }
202 202
 
203
-	/**
204
-	 * @return string
205
-	 */
206
-	public static function getLogFilePath() {
207
-		return self::$logFile;
208
-	}
203
+    /**
204
+     * @return string
205
+     */
206
+    public static function getLogFilePath() {
207
+        return self::$logFile;
208
+    }
209 209
 }
Please login to merge, or discard this patch.
lib/private/L10N/Factory.php 1 patch
Indentation   +400 added lines, -400 removed lines patch added patch discarded remove patch
@@ -40,404 +40,404 @@
 block discarded – undo
40 40
  */
41 41
 class Factory implements IFactory {
42 42
 
43
-	/** @var string */
44
-	protected $requestLanguage = '';
45
-
46
-	/**
47
-	 * cached instances
48
-	 * @var array Structure: Lang => App => \OCP\IL10N
49
-	 */
50
-	protected $instances = [];
51
-
52
-	/**
53
-	 * @var array Structure: App => string[]
54
-	 */
55
-	protected $availableLanguages = [];
56
-
57
-	/**
58
-	 * @var array Structure: string => callable
59
-	 */
60
-	protected $pluralFunctions = [];
61
-
62
-	/** @var IConfig */
63
-	protected $config;
64
-
65
-	/** @var IRequest */
66
-	protected $request;
67
-
68
-	/** @var IUserSession */
69
-	protected $userSession;
70
-
71
-	/** @var string */
72
-	protected $serverRoot;
73
-
74
-	/**
75
-	 * @param IConfig $config
76
-	 * @param IRequest $request
77
-	 * @param IUserSession $userSession
78
-	 * @param string $serverRoot
79
-	 */
80
-	public function __construct(IConfig $config,
81
-								IRequest $request,
82
-								IUserSession $userSession,
83
-								$serverRoot) {
84
-		$this->config = $config;
85
-		$this->request = $request;
86
-		$this->userSession = $userSession;
87
-		$this->serverRoot = $serverRoot;
88
-	}
89
-
90
-	/**
91
-	 * Get a language instance
92
-	 *
93
-	 * @param string $app
94
-	 * @param string|null $lang
95
-	 * @return \OCP\IL10N
96
-	 */
97
-	public function get($app, $lang = null) {
98
-		$app = \OC_App::cleanAppId($app);
99
-		if ($lang !== null) {
100
-			$lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
101
-		}
102
-
103
-		$forceLang = $this->config->getSystemValue('force_language', false);
104
-		if (is_string($forceLang)) {
105
-			$lang = $forceLang;
106
-		}
107
-
108
-		if ($lang === null || !$this->languageExists($app, $lang)) {
109
-			$lang = $this->findLanguage($app);
110
-		}
111
-
112
-		if (!isset($this->instances[$lang][$app])) {
113
-			$this->instances[$lang][$app] = new L10N(
114
-				$this, $app, $lang,
115
-				$this->getL10nFilesForApp($app, $lang)
116
-			);
117
-		}
118
-
119
-		return $this->instances[$lang][$app];
120
-	}
121
-
122
-	/**
123
-	 * Find the best language
124
-	 *
125
-	 * @param string|null $app App id or null for core
126
-	 * @return string language If nothing works it returns 'en'
127
-	 */
128
-	public function findLanguage($app = null) {
129
-		if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
130
-			return $this->requestLanguage;
131
-		}
132
-
133
-		/**
134
-		 * At this point Nextcloud might not yet be installed and thus the lookup
135
-		 * in the preferences table might fail. For this reason we need to check
136
-		 * whether the instance has already been installed
137
-		 *
138
-		 * @link https://github.com/owncloud/core/issues/21955
139
-		 */
140
-		if($this->config->getSystemValue('installed', false)) {
141
-			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
142
-			if(!is_null($userId)) {
143
-				$userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
144
-			} else {
145
-				$userLang = null;
146
-			}
147
-		} else {
148
-			$userId = null;
149
-			$userLang = null;
150
-		}
151
-
152
-		if ($userLang) {
153
-			$this->requestLanguage = $userLang;
154
-			if ($this->languageExists($app, $userLang)) {
155
-				return $userLang;
156
-			}
157
-		}
158
-
159
-		try {
160
-			// Try to get the language from the Request
161
-			$lang = $this->getLanguageFromRequest($app);
162
-			if ($userId !== null && $app === null && !$userLang) {
163
-				$this->config->setUserValue($userId, 'core', 'lang', $lang);
164
-			}
165
-			return $lang;
166
-		} catch (LanguageNotFoundException $e) {
167
-			// Finding language from request failed fall back to default language
168
-			$defaultLanguage = $this->config->getSystemValue('default_language', false);
169
-			if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
170
-				return $defaultLanguage;
171
-			}
172
-		}
173
-
174
-		// We could not find any language so fall back to english
175
-		return 'en';
176
-	}
177
-
178
-	/**
179
-	 * Find all available languages for an app
180
-	 *
181
-	 * @param string|null $app App id or null for core
182
-	 * @return array an array of available languages
183
-	 */
184
-	public function findAvailableLanguages($app = null) {
185
-		$key = $app;
186
-		if ($key === null) {
187
-			$key = 'null';
188
-		}
189
-
190
-		// also works with null as key
191
-		if (!empty($this->availableLanguages[$key])) {
192
-			return $this->availableLanguages[$key];
193
-		}
194
-
195
-		$available = ['en']; //english is always available
196
-		$dir = $this->findL10nDir($app);
197
-		if (is_dir($dir)) {
198
-			$files = scandir($dir);
199
-			if ($files !== false) {
200
-				foreach ($files as $file) {
201
-					if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
202
-						$available[] = substr($file, 0, -5);
203
-					}
204
-				}
205
-			}
206
-		}
207
-
208
-		// merge with translations from theme
209
-		$theme = $this->config->getSystemValue('theme');
210
-		if (!empty($theme)) {
211
-			$themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
212
-
213
-			if (is_dir($themeDir)) {
214
-				$files = scandir($themeDir);
215
-				if ($files !== false) {
216
-					foreach ($files as $file) {
217
-						if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
218
-							$available[] = substr($file, 0, -5);
219
-						}
220
-					}
221
-				}
222
-			}
223
-		}
224
-
225
-		$this->availableLanguages[$key] = $available;
226
-		return $available;
227
-	}
228
-
229
-	/**
230
-	 * @param string|null $app App id or null for core
231
-	 * @param string $lang
232
-	 * @return bool
233
-	 */
234
-	public function languageExists($app, $lang) {
235
-		if ($lang === 'en') {//english is always available
236
-			return true;
237
-		}
238
-
239
-		$languages = $this->findAvailableLanguages($app);
240
-		return array_search($lang, $languages) !== false;
241
-	}
242
-
243
-	/**
244
-	 * @param string|null $app
245
-	 * @return string
246
-	 * @throws LanguageNotFoundException
247
-	 */
248
-	private function getLanguageFromRequest($app) {
249
-		$header = $this->request->getHeader('ACCEPT_LANGUAGE');
250
-		if ($header !== '') {
251
-			$available = $this->findAvailableLanguages($app);
252
-
253
-			// E.g. make sure that 'de' is before 'de_DE'.
254
-			sort($available);
255
-
256
-			$preferences = preg_split('/,\s*/', strtolower($header));
257
-			foreach ($preferences as $preference) {
258
-				list($preferred_language) = explode(';', $preference);
259
-				$preferred_language = str_replace('-', '_', $preferred_language);
260
-
261
-				foreach ($available as $available_language) {
262
-					if ($preferred_language === strtolower($available_language)) {
263
-						return $this->respectDefaultLanguage($app, $available_language);
264
-					}
265
-				}
266
-
267
-				// Fallback from de_De to de
268
-				foreach ($available as $available_language) {
269
-					if (substr($preferred_language, 0, 2) === $available_language) {
270
-						return $available_language;
271
-					}
272
-				}
273
-			}
274
-		}
275
-
276
-		throw new LanguageNotFoundException();
277
-	}
278
-
279
-	/**
280
-	 * if default language is set to de_DE (formal German) this should be
281
-	 * preferred to 'de' (non-formal German) if possible
282
-	 *
283
-	 * @param string|null $app
284
-	 * @param string $lang
285
-	 * @return string
286
-	 */
287
-	protected function respectDefaultLanguage($app, $lang) {
288
-		$result = $lang;
289
-		$defaultLanguage = $this->config->getSystemValue('default_language', false);
290
-
291
-		// use formal version of german ("Sie" instead of "Du") if the default
292
-		// language is set to 'de_DE' if possible
293
-		if (is_string($defaultLanguage) &&
294
-			strtolower($lang) === 'de' &&
295
-			strtolower($defaultLanguage) === 'de_de' &&
296
-			$this->languageExists($app, 'de_DE')
297
-		) {
298
-			$result = 'de_DE';
299
-		}
300
-
301
-		return $result;
302
-	}
303
-
304
-	/**
305
-	 * Checks if $sub is a subdirectory of $parent
306
-	 *
307
-	 * @param string $sub
308
-	 * @param string $parent
309
-	 * @return bool
310
-	 */
311
-	private function isSubDirectory($sub, $parent) {
312
-		// Check whether $sub contains no ".."
313
-		if(strpos($sub, '..') !== false) {
314
-			return false;
315
-		}
316
-
317
-		// Check whether $sub is a subdirectory of $parent
318
-		if (strpos($sub, $parent) === 0) {
319
-			return true;
320
-		}
321
-
322
-		return false;
323
-	}
324
-
325
-	/**
326
-	 * Get a list of language files that should be loaded
327
-	 *
328
-	 * @param string $app
329
-	 * @param string $lang
330
-	 * @return string[]
331
-	 */
332
-	// FIXME This method is only public, until OC_L10N does not need it anymore,
333
-	// FIXME This is also the reason, why it is not in the public interface
334
-	public function getL10nFilesForApp($app, $lang) {
335
-		$languageFiles = [];
336
-
337
-		$i18nDir = $this->findL10nDir($app);
338
-		$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
339
-
340
-		if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
341
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
342
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
343
-				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
344
-			)
345
-			&& file_exists($transFile)) {
346
-			// load the translations file
347
-			$languageFiles[] = $transFile;
348
-		}
349
-
350
-		// merge with translations from theme
351
-		$theme = $this->config->getSystemValue('theme');
352
-		if (!empty($theme)) {
353
-			$transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
354
-			if (file_exists($transFile)) {
355
-				$languageFiles[] = $transFile;
356
-			}
357
-		}
358
-
359
-		return $languageFiles;
360
-	}
361
-
362
-	/**
363
-	 * find the l10n directory
364
-	 *
365
-	 * @param string $app App id or empty string for core
366
-	 * @return string directory
367
-	 */
368
-	protected function findL10nDir($app = null) {
369
-		if (in_array($app, ['core', 'lib', 'settings'])) {
370
-			if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
371
-				return $this->serverRoot . '/' . $app . '/l10n/';
372
-			}
373
-		} else if ($app && \OC_App::getAppPath($app) !== false) {
374
-			// Check if the app is in the app folder
375
-			return \OC_App::getAppPath($app) . '/l10n/';
376
-		}
377
-		return $this->serverRoot . '/core/l10n/';
378
-	}
379
-
380
-
381
-	/**
382
-	 * Creates a function from the plural string
383
-	 *
384
-	 * Parts of the code is copied from Habari:
385
-	 * https://github.com/habari/system/blob/master/classes/locale.php
386
-	 * @param string $string
387
-	 * @return string
388
-	 */
389
-	public function createPluralFunction($string) {
390
-		if (isset($this->pluralFunctions[$string])) {
391
-			return $this->pluralFunctions[$string];
392
-		}
393
-
394
-		if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
395
-			// sanitize
396
-			$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
397
-			$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
398
-
399
-			$body = str_replace(
400
-				array( 'plural', 'n', '$n$plurals', ),
401
-				array( '$plural', '$n', '$nplurals', ),
402
-				'nplurals='. $nplurals . '; plural=' . $plural
403
-			);
404
-
405
-			// add parents
406
-			// important since PHP's ternary evaluates from left to right
407
-			$body .= ';';
408
-			$res = '';
409
-			$p = 0;
410
-			for($i = 0; $i < strlen($body); $i++) {
411
-				$ch = $body[$i];
412
-				switch ( $ch ) {
413
-					case '?':
414
-						$res .= ' ? (';
415
-						$p++;
416
-						break;
417
-					case ':':
418
-						$res .= ') : (';
419
-						break;
420
-					case ';':
421
-						$res .= str_repeat( ')', $p ) . ';';
422
-						$p = 0;
423
-						break;
424
-					default:
425
-						$res .= $ch;
426
-				}
427
-			}
428
-
429
-			$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
430
-			$function = create_function('$n', $body);
431
-			$this->pluralFunctions[$string] = $function;
432
-			return $function;
433
-		} else {
434
-			// default: one plural form for all cases but n==1 (english)
435
-			$function = create_function(
436
-				'$n',
437
-				'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
438
-			);
439
-			$this->pluralFunctions[$string] = $function;
440
-			return $function;
441
-		}
442
-	}
43
+    /** @var string */
44
+    protected $requestLanguage = '';
45
+
46
+    /**
47
+     * cached instances
48
+     * @var array Structure: Lang => App => \OCP\IL10N
49
+     */
50
+    protected $instances = [];
51
+
52
+    /**
53
+     * @var array Structure: App => string[]
54
+     */
55
+    protected $availableLanguages = [];
56
+
57
+    /**
58
+     * @var array Structure: string => callable
59
+     */
60
+    protected $pluralFunctions = [];
61
+
62
+    /** @var IConfig */
63
+    protected $config;
64
+
65
+    /** @var IRequest */
66
+    protected $request;
67
+
68
+    /** @var IUserSession */
69
+    protected $userSession;
70
+
71
+    /** @var string */
72
+    protected $serverRoot;
73
+
74
+    /**
75
+     * @param IConfig $config
76
+     * @param IRequest $request
77
+     * @param IUserSession $userSession
78
+     * @param string $serverRoot
79
+     */
80
+    public function __construct(IConfig $config,
81
+                                IRequest $request,
82
+                                IUserSession $userSession,
83
+                                $serverRoot) {
84
+        $this->config = $config;
85
+        $this->request = $request;
86
+        $this->userSession = $userSession;
87
+        $this->serverRoot = $serverRoot;
88
+    }
89
+
90
+    /**
91
+     * Get a language instance
92
+     *
93
+     * @param string $app
94
+     * @param string|null $lang
95
+     * @return \OCP\IL10N
96
+     */
97
+    public function get($app, $lang = null) {
98
+        $app = \OC_App::cleanAppId($app);
99
+        if ($lang !== null) {
100
+            $lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
101
+        }
102
+
103
+        $forceLang = $this->config->getSystemValue('force_language', false);
104
+        if (is_string($forceLang)) {
105
+            $lang = $forceLang;
106
+        }
107
+
108
+        if ($lang === null || !$this->languageExists($app, $lang)) {
109
+            $lang = $this->findLanguage($app);
110
+        }
111
+
112
+        if (!isset($this->instances[$lang][$app])) {
113
+            $this->instances[$lang][$app] = new L10N(
114
+                $this, $app, $lang,
115
+                $this->getL10nFilesForApp($app, $lang)
116
+            );
117
+        }
118
+
119
+        return $this->instances[$lang][$app];
120
+    }
121
+
122
+    /**
123
+     * Find the best language
124
+     *
125
+     * @param string|null $app App id or null for core
126
+     * @return string language If nothing works it returns 'en'
127
+     */
128
+    public function findLanguage($app = null) {
129
+        if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
130
+            return $this->requestLanguage;
131
+        }
132
+
133
+        /**
134
+         * At this point Nextcloud might not yet be installed and thus the lookup
135
+         * in the preferences table might fail. For this reason we need to check
136
+         * whether the instance has already been installed
137
+         *
138
+         * @link https://github.com/owncloud/core/issues/21955
139
+         */
140
+        if($this->config->getSystemValue('installed', false)) {
141
+            $userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
142
+            if(!is_null($userId)) {
143
+                $userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
144
+            } else {
145
+                $userLang = null;
146
+            }
147
+        } else {
148
+            $userId = null;
149
+            $userLang = null;
150
+        }
151
+
152
+        if ($userLang) {
153
+            $this->requestLanguage = $userLang;
154
+            if ($this->languageExists($app, $userLang)) {
155
+                return $userLang;
156
+            }
157
+        }
158
+
159
+        try {
160
+            // Try to get the language from the Request
161
+            $lang = $this->getLanguageFromRequest($app);
162
+            if ($userId !== null && $app === null && !$userLang) {
163
+                $this->config->setUserValue($userId, 'core', 'lang', $lang);
164
+            }
165
+            return $lang;
166
+        } catch (LanguageNotFoundException $e) {
167
+            // Finding language from request failed fall back to default language
168
+            $defaultLanguage = $this->config->getSystemValue('default_language', false);
169
+            if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
170
+                return $defaultLanguage;
171
+            }
172
+        }
173
+
174
+        // We could not find any language so fall back to english
175
+        return 'en';
176
+    }
177
+
178
+    /**
179
+     * Find all available languages for an app
180
+     *
181
+     * @param string|null $app App id or null for core
182
+     * @return array an array of available languages
183
+     */
184
+    public function findAvailableLanguages($app = null) {
185
+        $key = $app;
186
+        if ($key === null) {
187
+            $key = 'null';
188
+        }
189
+
190
+        // also works with null as key
191
+        if (!empty($this->availableLanguages[$key])) {
192
+            return $this->availableLanguages[$key];
193
+        }
194
+
195
+        $available = ['en']; //english is always available
196
+        $dir = $this->findL10nDir($app);
197
+        if (is_dir($dir)) {
198
+            $files = scandir($dir);
199
+            if ($files !== false) {
200
+                foreach ($files as $file) {
201
+                    if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
202
+                        $available[] = substr($file, 0, -5);
203
+                    }
204
+                }
205
+            }
206
+        }
207
+
208
+        // merge with translations from theme
209
+        $theme = $this->config->getSystemValue('theme');
210
+        if (!empty($theme)) {
211
+            $themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
212
+
213
+            if (is_dir($themeDir)) {
214
+                $files = scandir($themeDir);
215
+                if ($files !== false) {
216
+                    foreach ($files as $file) {
217
+                        if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
218
+                            $available[] = substr($file, 0, -5);
219
+                        }
220
+                    }
221
+                }
222
+            }
223
+        }
224
+
225
+        $this->availableLanguages[$key] = $available;
226
+        return $available;
227
+    }
228
+
229
+    /**
230
+     * @param string|null $app App id or null for core
231
+     * @param string $lang
232
+     * @return bool
233
+     */
234
+    public function languageExists($app, $lang) {
235
+        if ($lang === 'en') {//english is always available
236
+            return true;
237
+        }
238
+
239
+        $languages = $this->findAvailableLanguages($app);
240
+        return array_search($lang, $languages) !== false;
241
+    }
242
+
243
+    /**
244
+     * @param string|null $app
245
+     * @return string
246
+     * @throws LanguageNotFoundException
247
+     */
248
+    private function getLanguageFromRequest($app) {
249
+        $header = $this->request->getHeader('ACCEPT_LANGUAGE');
250
+        if ($header !== '') {
251
+            $available = $this->findAvailableLanguages($app);
252
+
253
+            // E.g. make sure that 'de' is before 'de_DE'.
254
+            sort($available);
255
+
256
+            $preferences = preg_split('/,\s*/', strtolower($header));
257
+            foreach ($preferences as $preference) {
258
+                list($preferred_language) = explode(';', $preference);
259
+                $preferred_language = str_replace('-', '_', $preferred_language);
260
+
261
+                foreach ($available as $available_language) {
262
+                    if ($preferred_language === strtolower($available_language)) {
263
+                        return $this->respectDefaultLanguage($app, $available_language);
264
+                    }
265
+                }
266
+
267
+                // Fallback from de_De to de
268
+                foreach ($available as $available_language) {
269
+                    if (substr($preferred_language, 0, 2) === $available_language) {
270
+                        return $available_language;
271
+                    }
272
+                }
273
+            }
274
+        }
275
+
276
+        throw new LanguageNotFoundException();
277
+    }
278
+
279
+    /**
280
+     * if default language is set to de_DE (formal German) this should be
281
+     * preferred to 'de' (non-formal German) if possible
282
+     *
283
+     * @param string|null $app
284
+     * @param string $lang
285
+     * @return string
286
+     */
287
+    protected function respectDefaultLanguage($app, $lang) {
288
+        $result = $lang;
289
+        $defaultLanguage = $this->config->getSystemValue('default_language', false);
290
+
291
+        // use formal version of german ("Sie" instead of "Du") if the default
292
+        // language is set to 'de_DE' if possible
293
+        if (is_string($defaultLanguage) &&
294
+            strtolower($lang) === 'de' &&
295
+            strtolower($defaultLanguage) === 'de_de' &&
296
+            $this->languageExists($app, 'de_DE')
297
+        ) {
298
+            $result = 'de_DE';
299
+        }
300
+
301
+        return $result;
302
+    }
303
+
304
+    /**
305
+     * Checks if $sub is a subdirectory of $parent
306
+     *
307
+     * @param string $sub
308
+     * @param string $parent
309
+     * @return bool
310
+     */
311
+    private function isSubDirectory($sub, $parent) {
312
+        // Check whether $sub contains no ".."
313
+        if(strpos($sub, '..') !== false) {
314
+            return false;
315
+        }
316
+
317
+        // Check whether $sub is a subdirectory of $parent
318
+        if (strpos($sub, $parent) === 0) {
319
+            return true;
320
+        }
321
+
322
+        return false;
323
+    }
324
+
325
+    /**
326
+     * Get a list of language files that should be loaded
327
+     *
328
+     * @param string $app
329
+     * @param string $lang
330
+     * @return string[]
331
+     */
332
+    // FIXME This method is only public, until OC_L10N does not need it anymore,
333
+    // FIXME This is also the reason, why it is not in the public interface
334
+    public function getL10nFilesForApp($app, $lang) {
335
+        $languageFiles = [];
336
+
337
+        $i18nDir = $this->findL10nDir($app);
338
+        $transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
339
+
340
+        if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
341
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
342
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
343
+                || $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
344
+            )
345
+            && file_exists($transFile)) {
346
+            // load the translations file
347
+            $languageFiles[] = $transFile;
348
+        }
349
+
350
+        // merge with translations from theme
351
+        $theme = $this->config->getSystemValue('theme');
352
+        if (!empty($theme)) {
353
+            $transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
354
+            if (file_exists($transFile)) {
355
+                $languageFiles[] = $transFile;
356
+            }
357
+        }
358
+
359
+        return $languageFiles;
360
+    }
361
+
362
+    /**
363
+     * find the l10n directory
364
+     *
365
+     * @param string $app App id or empty string for core
366
+     * @return string directory
367
+     */
368
+    protected function findL10nDir($app = null) {
369
+        if (in_array($app, ['core', 'lib', 'settings'])) {
370
+            if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
371
+                return $this->serverRoot . '/' . $app . '/l10n/';
372
+            }
373
+        } else if ($app && \OC_App::getAppPath($app) !== false) {
374
+            // Check if the app is in the app folder
375
+            return \OC_App::getAppPath($app) . '/l10n/';
376
+        }
377
+        return $this->serverRoot . '/core/l10n/';
378
+    }
379
+
380
+
381
+    /**
382
+     * Creates a function from the plural string
383
+     *
384
+     * Parts of the code is copied from Habari:
385
+     * https://github.com/habari/system/blob/master/classes/locale.php
386
+     * @param string $string
387
+     * @return string
388
+     */
389
+    public function createPluralFunction($string) {
390
+        if (isset($this->pluralFunctions[$string])) {
391
+            return $this->pluralFunctions[$string];
392
+        }
393
+
394
+        if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
395
+            // sanitize
396
+            $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
397
+            $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
398
+
399
+            $body = str_replace(
400
+                array( 'plural', 'n', '$n$plurals', ),
401
+                array( '$plural', '$n', '$nplurals', ),
402
+                'nplurals='. $nplurals . '; plural=' . $plural
403
+            );
404
+
405
+            // add parents
406
+            // important since PHP's ternary evaluates from left to right
407
+            $body .= ';';
408
+            $res = '';
409
+            $p = 0;
410
+            for($i = 0; $i < strlen($body); $i++) {
411
+                $ch = $body[$i];
412
+                switch ( $ch ) {
413
+                    case '?':
414
+                        $res .= ' ? (';
415
+                        $p++;
416
+                        break;
417
+                    case ':':
418
+                        $res .= ') : (';
419
+                        break;
420
+                    case ';':
421
+                        $res .= str_repeat( ')', $p ) . ';';
422
+                        $p = 0;
423
+                        break;
424
+                    default:
425
+                        $res .= $ch;
426
+                }
427
+            }
428
+
429
+            $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
430
+            $function = create_function('$n', $body);
431
+            $this->pluralFunctions[$string] = $function;
432
+            return $function;
433
+        } else {
434
+            // default: one plural form for all cases but n==1 (english)
435
+            $function = create_function(
436
+                '$n',
437
+                '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
438
+            );
439
+            $this->pluralFunctions[$string] = $function;
440
+            return $function;
441
+        }
442
+    }
443 443
 }
Please login to merge, or discard this patch.
lib/private/Memcache/APCu.php 1 patch
Indentation   +125 added lines, -125 removed lines patch added patch discarded remove patch
@@ -30,140 +30,140 @@
 block discarded – undo
30 30
 use OCP\IMemcache;
31 31
 
32 32
 class APCu extends Cache implements IMemcache {
33
-	use CASTrait {
34
-		cas as casEmulated;
35
-	}
33
+    use CASTrait {
34
+        cas as casEmulated;
35
+    }
36 36
 
37
-	use CADTrait;
37
+    use CADTrait;
38 38
 
39
-	public function get($key) {
40
-		$result = apcu_fetch($this->getPrefix() . $key, $success);
41
-		if (!$success) {
42
-			return null;
43
-		}
44
-		return $result;
45
-	}
39
+    public function get($key) {
40
+        $result = apcu_fetch($this->getPrefix() . $key, $success);
41
+        if (!$success) {
42
+            return null;
43
+        }
44
+        return $result;
45
+    }
46 46
 
47
-	public function set($key, $value, $ttl = 0) {
48
-		return apcu_store($this->getPrefix() . $key, $value, $ttl);
49
-	}
47
+    public function set($key, $value, $ttl = 0) {
48
+        return apcu_store($this->getPrefix() . $key, $value, $ttl);
49
+    }
50 50
 
51
-	public function hasKey($key) {
52
-		return apcu_exists($this->getPrefix() . $key);
53
-	}
51
+    public function hasKey($key) {
52
+        return apcu_exists($this->getPrefix() . $key);
53
+    }
54 54
 
55
-	public function remove($key) {
56
-		return apcu_delete($this->getPrefix() . $key);
57
-	}
55
+    public function remove($key) {
56
+        return apcu_delete($this->getPrefix() . $key);
57
+    }
58 58
 
59
-	public function clear($prefix = '') {
60
-		$ns = $this->getPrefix() . $prefix;
61
-		$ns = preg_quote($ns, '/');
62
-		if(class_exists('\APCIterator')) {
63
-			$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
64
-		} else {
65
-			$iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
66
-		}
67
-		return apcu_delete($iter);
68
-	}
59
+    public function clear($prefix = '') {
60
+        $ns = $this->getPrefix() . $prefix;
61
+        $ns = preg_quote($ns, '/');
62
+        if(class_exists('\APCIterator')) {
63
+            $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
64
+        } else {
65
+            $iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
66
+        }
67
+        return apcu_delete($iter);
68
+    }
69 69
 
70
-	/**
71
-	 * Set a value in the cache if it's not already stored
72
-	 *
73
-	 * @param string $key
74
-	 * @param mixed $value
75
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
76
-	 * @return bool
77
-	 */
78
-	public function add($key, $value, $ttl = 0) {
79
-		return apcu_add($this->getPrefix() . $key, $value, $ttl);
80
-	}
70
+    /**
71
+     * Set a value in the cache if it's not already stored
72
+     *
73
+     * @param string $key
74
+     * @param mixed $value
75
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
76
+     * @return bool
77
+     */
78
+    public function add($key, $value, $ttl = 0) {
79
+        return apcu_add($this->getPrefix() . $key, $value, $ttl);
80
+    }
81 81
 
82
-	/**
83
-	 * Increase a stored number
84
-	 *
85
-	 * @param string $key
86
-	 * @param int $step
87
-	 * @return int | bool
88
-	 */
89
-	public function inc($key, $step = 1) {
90
-		$this->add($key, 0);
91
-		/**
92
-		 * TODO - hack around a PHP 7 specific issue in APCu
93
-		 *
94
-		 * on PHP 7 the apcu_inc method on a non-existing object will increment
95
-		 * "0" and result in "1" as value - therefore we check for existence
96
-		 * first
97
-		 *
98
-		 * on PHP 5.6 this is not the case
99
-		 *
100
-		 * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
101
-		 * for details
102
-		 */
103
-		return apcu_exists($this->getPrefix() . $key)
104
-			? apcu_inc($this->getPrefix() . $key, $step)
105
-			: false;
106
-	}
82
+    /**
83
+     * Increase a stored number
84
+     *
85
+     * @param string $key
86
+     * @param int $step
87
+     * @return int | bool
88
+     */
89
+    public function inc($key, $step = 1) {
90
+        $this->add($key, 0);
91
+        /**
92
+         * TODO - hack around a PHP 7 specific issue in APCu
93
+         *
94
+         * on PHP 7 the apcu_inc method on a non-existing object will increment
95
+         * "0" and result in "1" as value - therefore we check for existence
96
+         * first
97
+         *
98
+         * on PHP 5.6 this is not the case
99
+         *
100
+         * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
101
+         * for details
102
+         */
103
+        return apcu_exists($this->getPrefix() . $key)
104
+            ? apcu_inc($this->getPrefix() . $key, $step)
105
+            : false;
106
+    }
107 107
 
108
-	/**
109
-	 * Decrease a stored number
110
-	 *
111
-	 * @param string $key
112
-	 * @param int $step
113
-	 * @return int | bool
114
-	 */
115
-	public function dec($key, $step = 1) {
116
-		/**
117
-		 * TODO - hack around a PHP 7 specific issue in APCu
118
-		 *
119
-		 * on PHP 7 the apcu_dec method on a non-existing object will decrement
120
-		 * "0" and result in "-1" as value - therefore we check for existence
121
-		 * first
122
-		 *
123
-		 * on PHP 5.6 this is not the case
124
-		 *
125
-		 * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
126
-		 * for details
127
-		 */
128
-		return apcu_exists($this->getPrefix() . $key)
129
-			? apcu_dec($this->getPrefix() . $key, $step)
130
-			: false;
131
-	}
108
+    /**
109
+     * Decrease a stored number
110
+     *
111
+     * @param string $key
112
+     * @param int $step
113
+     * @return int | bool
114
+     */
115
+    public function dec($key, $step = 1) {
116
+        /**
117
+         * TODO - hack around a PHP 7 specific issue in APCu
118
+         *
119
+         * on PHP 7 the apcu_dec method on a non-existing object will decrement
120
+         * "0" and result in "-1" as value - therefore we check for existence
121
+         * first
122
+         *
123
+         * on PHP 5.6 this is not the case
124
+         *
125
+         * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
126
+         * for details
127
+         */
128
+        return apcu_exists($this->getPrefix() . $key)
129
+            ? apcu_dec($this->getPrefix() . $key, $step)
130
+            : false;
131
+    }
132 132
 
133
-	/**
134
-	 * Compare and set
135
-	 *
136
-	 * @param string $key
137
-	 * @param mixed $old
138
-	 * @param mixed $new
139
-	 * @return bool
140
-	 */
141
-	public function cas($key, $old, $new) {
142
-		// apc only does cas for ints
143
-		if (is_int($old) and is_int($new)) {
144
-			return apcu_cas($this->getPrefix() . $key, $old, $new);
145
-		} else {
146
-			return $this->casEmulated($key, $old, $new);
147
-		}
148
-	}
133
+    /**
134
+     * Compare and set
135
+     *
136
+     * @param string $key
137
+     * @param mixed $old
138
+     * @param mixed $new
139
+     * @return bool
140
+     */
141
+    public function cas($key, $old, $new) {
142
+        // apc only does cas for ints
143
+        if (is_int($old) and is_int($new)) {
144
+            return apcu_cas($this->getPrefix() . $key, $old, $new);
145
+        } else {
146
+            return $this->casEmulated($key, $old, $new);
147
+        }
148
+    }
149 149
 
150
-	/**
151
-	 * @return bool
152
-	 */
153
-	static public function isAvailable() {
154
-		if (!extension_loaded('apcu')) {
155
-			return false;
156
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
157
-			return false;
158
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
159
-			return false;
160
-		} elseif (
161
-				version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
162
-				version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
163
-		) {
164
-			return false;
165
-		} else {
166
-			return true;
167
-		}
168
-	}
150
+    /**
151
+     * @return bool
152
+     */
153
+    static public function isAvailable() {
154
+        if (!extension_loaded('apcu')) {
155
+            return false;
156
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
157
+            return false;
158
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
159
+            return false;
160
+        } elseif (
161
+                version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
162
+                version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
163
+        ) {
164
+            return false;
165
+        } else {
166
+            return true;
167
+        }
168
+    }
169 169
 }
Please login to merge, or discard this patch.
apps/workflowengine/lib/Check/FileSize.php 1 patch
Indentation   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -30,90 +30,90 @@
 block discarded – undo
30 30
 
31 31
 class FileSize implements ICheck {
32 32
 
33
-	/** @var int */
34
-	protected $size;
35
-
36
-	/** @var IL10N */
37
-	protected $l;
38
-
39
-	/** @var IRequest */
40
-	protected $request;
41
-
42
-	/**
43
-	 * @param IL10N $l
44
-	 * @param IRequest $request
45
-	 */
46
-	public function __construct(IL10N $l, IRequest $request) {
47
-		$this->l = $l;
48
-		$this->request = $request;
49
-	}
50
-
51
-	/**
52
-	 * @param IStorage $storage
53
-	 * @param string $path
54
-	 */
55
-	public function setFileInfo(IStorage $storage, $path) {
56
-	}
57
-
58
-	/**
59
-	 * @param string $operator
60
-	 * @param string $value
61
-	 * @return bool
62
-	 */
63
-	public function executeCheck($operator, $value) {
64
-		$size = $this->getFileSizeFromHeader();
65
-
66
-		$value = Util::computerFileSize($value);
67
-		if ($size !== false) {
68
-			switch ($operator) {
69
-				case 'less':
70
-					return $size < $value;
71
-				case '!less':
72
-					return $size >= $value;
73
-				case 'greater':
74
-					return $size > $value;
75
-				case '!greater':
76
-					return $size <= $value;
77
-			}
78
-		}
79
-		return false;
80
-	}
81
-
82
-	/**
83
-	 * @param string $operator
84
-	 * @param string $value
85
-	 * @throws \UnexpectedValueException
86
-	 */
87
-	public function validateCheck($operator, $value) {
88
-		if (!in_array($operator, ['less', '!less', 'greater', '!greater'])) {
89
-			throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
90
-		}
91
-
92
-		if (!preg_match('/^[0-9]+[ ]?[kmgt]?b$/i', $value)) {
93
-			throw new \UnexpectedValueException($this->l->t('The given file size is invalid'), 2);
94
-		}
95
-	}
96
-
97
-	/**
98
-	 * @return string
99
-	 */
100
-	protected function getFileSizeFromHeader() {
101
-		if ($this->size !== null) {
102
-			return $this->size;
103
-		}
104
-
105
-		$size = $this->request->getHeader('OC-Total-Length');
106
-		if ($size === '') {
107
-			if (in_array($this->request->getMethod(), ['POST', 'PUT'])) {
108
-				$size = $this->request->getHeader('Content-Length');
109
-			}
110
-		}
111
-
112
-		if ($size === '') {
113
-			$size = false;
114
-		}
115
-
116
-		$this->size = $size;
117
-		return $this->size;
118
-	}
33
+    /** @var int */
34
+    protected $size;
35
+
36
+    /** @var IL10N */
37
+    protected $l;
38
+
39
+    /** @var IRequest */
40
+    protected $request;
41
+
42
+    /**
43
+     * @param IL10N $l
44
+     * @param IRequest $request
45
+     */
46
+    public function __construct(IL10N $l, IRequest $request) {
47
+        $this->l = $l;
48
+        $this->request = $request;
49
+    }
50
+
51
+    /**
52
+     * @param IStorage $storage
53
+     * @param string $path
54
+     */
55
+    public function setFileInfo(IStorage $storage, $path) {
56
+    }
57
+
58
+    /**
59
+     * @param string $operator
60
+     * @param string $value
61
+     * @return bool
62
+     */
63
+    public function executeCheck($operator, $value) {
64
+        $size = $this->getFileSizeFromHeader();
65
+
66
+        $value = Util::computerFileSize($value);
67
+        if ($size !== false) {
68
+            switch ($operator) {
69
+                case 'less':
70
+                    return $size < $value;
71
+                case '!less':
72
+                    return $size >= $value;
73
+                case 'greater':
74
+                    return $size > $value;
75
+                case '!greater':
76
+                    return $size <= $value;
77
+            }
78
+        }
79
+        return false;
80
+    }
81
+
82
+    /**
83
+     * @param string $operator
84
+     * @param string $value
85
+     * @throws \UnexpectedValueException
86
+     */
87
+    public function validateCheck($operator, $value) {
88
+        if (!in_array($operator, ['less', '!less', 'greater', '!greater'])) {
89
+            throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
90
+        }
91
+
92
+        if (!preg_match('/^[0-9]+[ ]?[kmgt]?b$/i', $value)) {
93
+            throw new \UnexpectedValueException($this->l->t('The given file size is invalid'), 2);
94
+        }
95
+    }
96
+
97
+    /**
98
+     * @return string
99
+     */
100
+    protected function getFileSizeFromHeader() {
101
+        if ($this->size !== null) {
102
+            return $this->size;
103
+        }
104
+
105
+        $size = $this->request->getHeader('OC-Total-Length');
106
+        if ($size === '') {
107
+            if (in_array($this->request->getMethod(), ['POST', 'PUT'])) {
108
+                $size = $this->request->getHeader('Content-Length');
109
+            }
110
+        }
111
+
112
+        if ($size === '') {
113
+            $size = false;
114
+        }
115
+
116
+        $this->size = $size;
117
+        return $this->size;
118
+    }
119 119
 }
Please login to merge, or discard this patch.
core/Controller/CssController.php 2 patches
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -40,74 +40,74 @@
 block discarded – undo
40 40
 
41 41
 class CssController extends Controller {
42 42
 
43
-	/** @var IAppData */
44
-	protected $appData;
43
+    /** @var IAppData */
44
+    protected $appData;
45 45
 
46
-	/** @var ITimeFactory */
47
-	protected $timeFactory;
46
+    /** @var ITimeFactory */
47
+    protected $timeFactory;
48 48
 
49
-	/**
50
-	 * @param string $appName
51
-	 * @param IRequest $request
52
-	 * @param Factory $appDataFactory
53
-	 * @param ITimeFactory $timeFactory
54
-	 */
55
-	public function __construct($appName, IRequest $request, Factory $appDataFactory, ITimeFactory $timeFactory) {
56
-		parent::__construct($appName, $request);
49
+    /**
50
+     * @param string $appName
51
+     * @param IRequest $request
52
+     * @param Factory $appDataFactory
53
+     * @param ITimeFactory $timeFactory
54
+     */
55
+    public function __construct($appName, IRequest $request, Factory $appDataFactory, ITimeFactory $timeFactory) {
56
+        parent::__construct($appName, $request);
57 57
 
58
-		$this->appData = $appDataFactory->get('css');
59
-		$this->timeFactory = $timeFactory;
60
-	}
58
+        $this->appData = $appDataFactory->get('css');
59
+        $this->timeFactory = $timeFactory;
60
+    }
61 61
 
62
-	/**
63
-	 * @PublicPage
64
-	 * @NoCSRFRequired
65
-	 *
66
-	 * @param string $fileName css filename with extension
67
-	 * @param string $appName css folder name
68
-	 * @return FileDisplayResponse|NotFoundResponse
69
-	 */
70
-	public function getCss($fileName, $appName) {
71
-		try {
72
-			$folder = $this->appData->getFolder($appName);
73
-			$gzip = false;
74
-			$file = $this->getFile($folder, $fileName, $gzip);
75
-		} catch(NotFoundException $e) {
76
-			return new NotFoundResponse();
77
-		}
62
+    /**
63
+     * @PublicPage
64
+     * @NoCSRFRequired
65
+     *
66
+     * @param string $fileName css filename with extension
67
+     * @param string $appName css folder name
68
+     * @return FileDisplayResponse|NotFoundResponse
69
+     */
70
+    public function getCss($fileName, $appName) {
71
+        try {
72
+            $folder = $this->appData->getFolder($appName);
73
+            $gzip = false;
74
+            $file = $this->getFile($folder, $fileName, $gzip);
75
+        } catch(NotFoundException $e) {
76
+            return new NotFoundResponse();
77
+        }
78 78
 
79
-		$response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'text/css']);
80
-		if ($gzip) {
81
-			$response->addHeader('Content-Encoding', 'gzip');
82
-		}
83
-		$response->cacheFor(86400);
84
-		$expires = new \DateTime();
85
-		$expires->setTimestamp($this->timeFactory->getTime());
86
-		$expires->add(new \DateInterval('PT24H'));
87
-		$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
88
-		$response->addHeader('Pragma', 'cache');
89
-		return $response;
90
-	}
79
+        $response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'text/css']);
80
+        if ($gzip) {
81
+            $response->addHeader('Content-Encoding', 'gzip');
82
+        }
83
+        $response->cacheFor(86400);
84
+        $expires = new \DateTime();
85
+        $expires->setTimestamp($this->timeFactory->getTime());
86
+        $expires->add(new \DateInterval('PT24H'));
87
+        $response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
88
+        $response->addHeader('Pragma', 'cache');
89
+        return $response;
90
+    }
91 91
 
92
-	/**
93
-	 * @param ISimpleFolder $folder
94
-	 * @param string $fileName
95
-	 * @param bool $gzip is set to true if we use the gzip file
96
-	 * @return ISimpleFile
97
-	 */
98
-	private function getFile(ISimpleFolder $folder, $fileName, &$gzip) {
99
-		$encoding = $this->request->getHeader('Accept-Encoding');
92
+    /**
93
+     * @param ISimpleFolder $folder
94
+     * @param string $fileName
95
+     * @param bool $gzip is set to true if we use the gzip file
96
+     * @return ISimpleFile
97
+     */
98
+    private function getFile(ISimpleFolder $folder, $fileName, &$gzip) {
99
+        $encoding = $this->request->getHeader('Accept-Encoding');
100 100
 
101
-		if (strpos($encoding, 'gzip') !== false) {
102
-			try {
103
-				$gzip = true;
104
-				return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
105
-			} catch (NotFoundException $e) {
106
-				// continue
107
-			}
108
-		}
101
+        if (strpos($encoding, 'gzip') !== false) {
102
+            try {
103
+                $gzip = true;
104
+                return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
105
+            } catch (NotFoundException $e) {
106
+                // continue
107
+            }
108
+        }
109 109
 
110
-		$gzip = false;
111
-		return $folder->getFile($fileName);
112
-	}
110
+        $gzip = false;
111
+        return $folder->getFile($fileName);
112
+    }
113 113
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
 			$folder = $this->appData->getFolder($appName);
73 73
 			$gzip = false;
74 74
 			$file = $this->getFile($folder, $fileName, $gzip);
75
-		} catch(NotFoundException $e) {
75
+		} catch (NotFoundException $e) {
76 76
 			return new NotFoundResponse();
77 77
 		}
78 78
 
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		if (strpos($encoding, 'gzip') !== false) {
102 102
 			try {
103 103
 				$gzip = true;
104
-				return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
104
+				return $folder->getFile($fileName.'.gzip'); # Safari doesn't like .gz
105 105
 			} catch (NotFoundException $e) {
106 106
 				// continue
107 107
 			}
Please login to merge, or discard this patch.
core/Controller/JsController.php 2 patches
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -38,74 +38,74 @@
 block discarded – undo
38 38
 
39 39
 class JsController extends Controller {
40 40
 
41
-	/** @var IAppData */
42
-	protected $appData;
41
+    /** @var IAppData */
42
+    protected $appData;
43 43
 
44
-	/** @var ITimeFactory */
45
-	protected $timeFactory;
44
+    /** @var ITimeFactory */
45
+    protected $timeFactory;
46 46
 
47
-	/**
48
-	 * @param string $appName
49
-	 * @param IRequest $request
50
-	 * @param Factory $appDataFactory
51
-	 * @param ITimeFactory $timeFactory
52
-	 */
53
-	public function __construct($appName, IRequest $request, Factory $appDataFactory, ITimeFactory $timeFactory) {
54
-		parent::__construct($appName, $request);
47
+    /**
48
+     * @param string $appName
49
+     * @param IRequest $request
50
+     * @param Factory $appDataFactory
51
+     * @param ITimeFactory $timeFactory
52
+     */
53
+    public function __construct($appName, IRequest $request, Factory $appDataFactory, ITimeFactory $timeFactory) {
54
+        parent::__construct($appName, $request);
55 55
 
56
-		$this->appData = $appDataFactory->get('js');
57
-		$this->timeFactory = $timeFactory;
58
-	}
56
+        $this->appData = $appDataFactory->get('js');
57
+        $this->timeFactory = $timeFactory;
58
+    }
59 59
 
60
-	/**
61
-	 * @PublicPage
62
-	 * @NoCSRFRequired
63
-	 *
64
-	 * @param string $fileName css filename with extension
65
-	 * @param string $appName css folder name
66
-	 * @return FileDisplayResponse|NotFoundResponse
67
-	 */
68
-	public function getJs($fileName, $appName) {
69
-		try {
70
-			$folder = $this->appData->getFolder($appName);
71
-			$gzip = false;
72
-			$file = $this->getFile($folder, $fileName, $gzip);
73
-		} catch(NotFoundException $e) {
74
-			return new NotFoundResponse();
75
-		}
60
+    /**
61
+     * @PublicPage
62
+     * @NoCSRFRequired
63
+     *
64
+     * @param string $fileName css filename with extension
65
+     * @param string $appName css folder name
66
+     * @return FileDisplayResponse|NotFoundResponse
67
+     */
68
+    public function getJs($fileName, $appName) {
69
+        try {
70
+            $folder = $this->appData->getFolder($appName);
71
+            $gzip = false;
72
+            $file = $this->getFile($folder, $fileName, $gzip);
73
+        } catch(NotFoundException $e) {
74
+            return new NotFoundResponse();
75
+        }
76 76
 
77
-		$response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'application/javascript']);
78
-		if ($gzip) {
79
-			$response->addHeader('Content-Encoding', 'gzip');
80
-		}
81
-		$response->cacheFor(86400);
82
-		$expires = new \DateTime();
83
-		$expires->setTimestamp($this->timeFactory->getTime());
84
-		$expires->add(new \DateInterval('PT24H'));
85
-		$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
86
-		$response->addHeader('Pragma', 'cache');
87
-		return $response;
88
-	}
77
+        $response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'application/javascript']);
78
+        if ($gzip) {
79
+            $response->addHeader('Content-Encoding', 'gzip');
80
+        }
81
+        $response->cacheFor(86400);
82
+        $expires = new \DateTime();
83
+        $expires->setTimestamp($this->timeFactory->getTime());
84
+        $expires->add(new \DateInterval('PT24H'));
85
+        $response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
86
+        $response->addHeader('Pragma', 'cache');
87
+        return $response;
88
+    }
89 89
 
90
-	/**
91
-	 * @param ISimpleFolder $folder
92
-	 * @param string $fileName
93
-	 * @param bool $gzip is set to true if we use the gzip file
94
-	 * @return ISimpleFile
95
-	 */
96
-	private function getFile(ISimpleFolder $folder, $fileName, &$gzip) {
97
-		$encoding = $this->request->getHeader('Accept-Encoding');
90
+    /**
91
+     * @param ISimpleFolder $folder
92
+     * @param string $fileName
93
+     * @param bool $gzip is set to true if we use the gzip file
94
+     * @return ISimpleFile
95
+     */
96
+    private function getFile(ISimpleFolder $folder, $fileName, &$gzip) {
97
+        $encoding = $this->request->getHeader('Accept-Encoding');
98 98
 
99
-		if (strpos($encoding, 'gzip') !== false) {
100
-			try {
101
-				$gzip = true;
102
-				return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
103
-			} catch (NotFoundException $e) {
104
-				// continue
105
-			}
106
-		}
99
+        if (strpos($encoding, 'gzip') !== false) {
100
+            try {
101
+                $gzip = true;
102
+                return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
103
+            } catch (NotFoundException $e) {
104
+                // continue
105
+            }
106
+        }
107 107
 
108
-		$gzip = false;
109
-		return $folder->getFile($fileName);
110
-	}
108
+        $gzip = false;
109
+        return $folder->getFile($fileName);
110
+    }
111 111
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
 			$folder = $this->appData->getFolder($appName);
73 73
 			$gzip = false;
74 74
 			$file = $this->getFile($folder, $fileName, $gzip);
75
-		} catch(NotFoundException $e) {
75
+		} catch (NotFoundException $e) {
76 76
 			return new NotFoundResponse();
77 77
 		}
78 78
 
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		if (strpos($encoding, 'gzip') !== false) {
102 102
 			try {
103 103
 				$gzip = true;
104
-				return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
104
+				return $folder->getFile($fileName.'.gzip'); # Safari doesn't like .gz
105 105
 			} catch (NotFoundException $e) {
106 106
 				// continue
107 107
 			}
Please login to merge, or discard this patch.
core/Controller/ClientFlowLoginController.php 1 patch
Indentation   +261 added lines, -261 removed lines patch added patch discarded remove patch
@@ -48,291 +48,291 @@
 block discarded – undo
48 48
 use OCP\Session\Exceptions\SessionNotAvailableException;
49 49
 
50 50
 class ClientFlowLoginController extends Controller {
51
-	/** @var IUserSession */
52
-	private $userSession;
53
-	/** @var IL10N */
54
-	private $l10n;
55
-	/** @var Defaults */
56
-	private $defaults;
57
-	/** @var ISession */
58
-	private $session;
59
-	/** @var IProvider */
60
-	private $tokenProvider;
61
-	/** @var ISecureRandom */
62
-	private $random;
63
-	/** @var IURLGenerator */
64
-	private $urlGenerator;
65
-	/** @var ClientMapper */
66
-	private $clientMapper;
67
-	/** @var AccessTokenMapper */
68
-	private $accessTokenMapper;
69
-	/** @var ICrypto */
70
-	private $crypto;
51
+    /** @var IUserSession */
52
+    private $userSession;
53
+    /** @var IL10N */
54
+    private $l10n;
55
+    /** @var Defaults */
56
+    private $defaults;
57
+    /** @var ISession */
58
+    private $session;
59
+    /** @var IProvider */
60
+    private $tokenProvider;
61
+    /** @var ISecureRandom */
62
+    private $random;
63
+    /** @var IURLGenerator */
64
+    private $urlGenerator;
65
+    /** @var ClientMapper */
66
+    private $clientMapper;
67
+    /** @var AccessTokenMapper */
68
+    private $accessTokenMapper;
69
+    /** @var ICrypto */
70
+    private $crypto;
71 71
 
72
-	const stateName = 'client.flow.state.token';
72
+    const stateName = 'client.flow.state.token';
73 73
 
74
-	/**
75
-	 * @param string $appName
76
-	 * @param IRequest $request
77
-	 * @param IUserSession $userSession
78
-	 * @param IL10N $l10n
79
-	 * @param Defaults $defaults
80
-	 * @param ISession $session
81
-	 * @param IProvider $tokenProvider
82
-	 * @param ISecureRandom $random
83
-	 * @param IURLGenerator $urlGenerator
84
-	 * @param ClientMapper $clientMapper
85
-	 * @param AccessTokenMapper $accessTokenMapper
86
-	 * @param ICrypto $crypto
87
-	 */
88
-	public function __construct($appName,
89
-								IRequest $request,
90
-								IUserSession $userSession,
91
-								IL10N $l10n,
92
-								Defaults $defaults,
93
-								ISession $session,
94
-								IProvider $tokenProvider,
95
-								ISecureRandom $random,
96
-								IURLGenerator $urlGenerator,
97
-								ClientMapper $clientMapper,
98
-								AccessTokenMapper $accessTokenMapper,
99
-								ICrypto $crypto) {
100
-		parent::__construct($appName, $request);
101
-		$this->userSession = $userSession;
102
-		$this->l10n = $l10n;
103
-		$this->defaults = $defaults;
104
-		$this->session = $session;
105
-		$this->tokenProvider = $tokenProvider;
106
-		$this->random = $random;
107
-		$this->urlGenerator = $urlGenerator;
108
-		$this->clientMapper = $clientMapper;
109
-		$this->accessTokenMapper = $accessTokenMapper;
110
-		$this->crypto = $crypto;
111
-	}
74
+    /**
75
+     * @param string $appName
76
+     * @param IRequest $request
77
+     * @param IUserSession $userSession
78
+     * @param IL10N $l10n
79
+     * @param Defaults $defaults
80
+     * @param ISession $session
81
+     * @param IProvider $tokenProvider
82
+     * @param ISecureRandom $random
83
+     * @param IURLGenerator $urlGenerator
84
+     * @param ClientMapper $clientMapper
85
+     * @param AccessTokenMapper $accessTokenMapper
86
+     * @param ICrypto $crypto
87
+     */
88
+    public function __construct($appName,
89
+                                IRequest $request,
90
+                                IUserSession $userSession,
91
+                                IL10N $l10n,
92
+                                Defaults $defaults,
93
+                                ISession $session,
94
+                                IProvider $tokenProvider,
95
+                                ISecureRandom $random,
96
+                                IURLGenerator $urlGenerator,
97
+                                ClientMapper $clientMapper,
98
+                                AccessTokenMapper $accessTokenMapper,
99
+                                ICrypto $crypto) {
100
+        parent::__construct($appName, $request);
101
+        $this->userSession = $userSession;
102
+        $this->l10n = $l10n;
103
+        $this->defaults = $defaults;
104
+        $this->session = $session;
105
+        $this->tokenProvider = $tokenProvider;
106
+        $this->random = $random;
107
+        $this->urlGenerator = $urlGenerator;
108
+        $this->clientMapper = $clientMapper;
109
+        $this->accessTokenMapper = $accessTokenMapper;
110
+        $this->crypto = $crypto;
111
+    }
112 112
 
113
-	/**
114
-	 * @return string
115
-	 */
116
-	private function getClientName() {
117
-		$userAgent = $this->request->getHeader('USER_AGENT');
118
-		return $userAgent !== '' ? $userAgent : 'unknown';
119
-	}
113
+    /**
114
+     * @return string
115
+     */
116
+    private function getClientName() {
117
+        $userAgent = $this->request->getHeader('USER_AGENT');
118
+        return $userAgent !== '' ? $userAgent : 'unknown';
119
+    }
120 120
 
121
-	/**
122
-	 * @param string $stateToken
123
-	 * @return bool
124
-	 */
125
-	private function isValidToken($stateToken) {
126
-		$currentToken = $this->session->get(self::stateName);
127
-		if(!is_string($stateToken) || !is_string($currentToken)) {
128
-			return false;
129
-		}
130
-		return hash_equals($currentToken, $stateToken);
131
-	}
121
+    /**
122
+     * @param string $stateToken
123
+     * @return bool
124
+     */
125
+    private function isValidToken($stateToken) {
126
+        $currentToken = $this->session->get(self::stateName);
127
+        if(!is_string($stateToken) || !is_string($currentToken)) {
128
+            return false;
129
+        }
130
+        return hash_equals($currentToken, $stateToken);
131
+    }
132 132
 
133
-	/**
134
-	 * @return TemplateResponse
135
-	 */
136
-	private function stateTokenForbiddenResponse() {
137
-		$response = new TemplateResponse(
138
-			$this->appName,
139
-			'403',
140
-			[
141
-				'file' => $this->l10n->t('State token does not match'),
142
-			],
143
-			'guest'
144
-		);
145
-		$response->setStatus(Http::STATUS_FORBIDDEN);
146
-		return $response;
147
-	}
133
+    /**
134
+     * @return TemplateResponse
135
+     */
136
+    private function stateTokenForbiddenResponse() {
137
+        $response = new TemplateResponse(
138
+            $this->appName,
139
+            '403',
140
+            [
141
+                'file' => $this->l10n->t('State token does not match'),
142
+            ],
143
+            'guest'
144
+        );
145
+        $response->setStatus(Http::STATUS_FORBIDDEN);
146
+        return $response;
147
+    }
148 148
 
149
-	/**
150
-	 * @PublicPage
151
-	 * @NoCSRFRequired
152
-	 * @UseSession
153
-	 *
154
-	 * @param string $clientIdentifier
155
-	 *
156
-	 * @return TemplateResponse
157
-	 */
158
-	public function showAuthPickerPage($clientIdentifier = '') {
159
-		$clientName = $this->getClientName();
160
-		$client = null;
161
-		if($clientIdentifier !== '') {
162
-			$client = $this->clientMapper->getByIdentifier($clientIdentifier);
163
-			$clientName = $client->getName();
164
-		}
149
+    /**
150
+     * @PublicPage
151
+     * @NoCSRFRequired
152
+     * @UseSession
153
+     *
154
+     * @param string $clientIdentifier
155
+     *
156
+     * @return TemplateResponse
157
+     */
158
+    public function showAuthPickerPage($clientIdentifier = '') {
159
+        $clientName = $this->getClientName();
160
+        $client = null;
161
+        if($clientIdentifier !== '') {
162
+            $client = $this->clientMapper->getByIdentifier($clientIdentifier);
163
+            $clientName = $client->getName();
164
+        }
165 165
 
166
-		// No valid clientIdentifier given and no valid API Request (APIRequest header not set)
167
-		$clientRequest = $this->request->getHeader('OCS-APIREQUEST');
168
-		if ($clientRequest !== 'true' && $client === null) {
169
-			return new TemplateResponse(
170
-				$this->appName,
171
-				'error',
172
-				[
173
-					'errors' =>
174
-					[
175
-						[
176
-							'error' => 'Access Forbidden',
177
-							'hint' => 'Invalid request',
178
-						],
179
-					],
180
-				],
181
-				'guest'
182
-			);
183
-		}
166
+        // No valid clientIdentifier given and no valid API Request (APIRequest header not set)
167
+        $clientRequest = $this->request->getHeader('OCS-APIREQUEST');
168
+        if ($clientRequest !== 'true' && $client === null) {
169
+            return new TemplateResponse(
170
+                $this->appName,
171
+                'error',
172
+                [
173
+                    'errors' =>
174
+                    [
175
+                        [
176
+                            'error' => 'Access Forbidden',
177
+                            'hint' => 'Invalid request',
178
+                        ],
179
+                    ],
180
+                ],
181
+                'guest'
182
+            );
183
+        }
184 184
 
185
-		$stateToken = $this->random->generate(
186
-			64,
187
-			ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
188
-		);
189
-		$this->session->set(self::stateName, $stateToken);
185
+        $stateToken = $this->random->generate(
186
+            64,
187
+            ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
188
+        );
189
+        $this->session->set(self::stateName, $stateToken);
190 190
 
191
-		return new TemplateResponse(
192
-			$this->appName,
193
-			'loginflow/authpicker',
194
-			[
195
-				'client' => $clientName,
196
-				'clientIdentifier' => $clientIdentifier,
197
-				'instanceName' => $this->defaults->getName(),
198
-				'urlGenerator' => $this->urlGenerator,
199
-				'stateToken' => $stateToken,
200
-				'serverHost' => $this->request->getServerHost(),
201
-				'oauthState' => $this->session->get('oauth.state'),
202
-			],
203
-			'guest'
204
-		);
205
-	}
191
+        return new TemplateResponse(
192
+            $this->appName,
193
+            'loginflow/authpicker',
194
+            [
195
+                'client' => $clientName,
196
+                'clientIdentifier' => $clientIdentifier,
197
+                'instanceName' => $this->defaults->getName(),
198
+                'urlGenerator' => $this->urlGenerator,
199
+                'stateToken' => $stateToken,
200
+                'serverHost' => $this->request->getServerHost(),
201
+                'oauthState' => $this->session->get('oauth.state'),
202
+            ],
203
+            'guest'
204
+        );
205
+    }
206 206
 
207
-	/**
208
-	 * @NoAdminRequired
209
-	 * @NoCSRFRequired
210
-	 * @UseSession
211
-	 *
212
-	 * @param string $stateToken
213
-	 * @param string $clientIdentifier
214
-	 * @return TemplateResponse
215
-	 */
216
-	public function redirectPage($stateToken = '',
217
-								 $clientIdentifier = '') {
218
-		if(!$this->isValidToken($stateToken)) {
219
-			return $this->stateTokenForbiddenResponse();
220
-		}
207
+    /**
208
+     * @NoAdminRequired
209
+     * @NoCSRFRequired
210
+     * @UseSession
211
+     *
212
+     * @param string $stateToken
213
+     * @param string $clientIdentifier
214
+     * @return TemplateResponse
215
+     */
216
+    public function redirectPage($stateToken = '',
217
+                                    $clientIdentifier = '') {
218
+        if(!$this->isValidToken($stateToken)) {
219
+            return $this->stateTokenForbiddenResponse();
220
+        }
221 221
 
222
-		return new TemplateResponse(
223
-			$this->appName,
224
-			'loginflow/redirect',
225
-			[
226
-				'urlGenerator' => $this->urlGenerator,
227
-				'stateToken' => $stateToken,
228
-				'clientIdentifier' => $clientIdentifier,
229
-				'oauthState' => $this->session->get('oauth.state'),
230
-			],
231
-			'guest'
232
-		);
233
-	}
222
+        return new TemplateResponse(
223
+            $this->appName,
224
+            'loginflow/redirect',
225
+            [
226
+                'urlGenerator' => $this->urlGenerator,
227
+                'stateToken' => $stateToken,
228
+                'clientIdentifier' => $clientIdentifier,
229
+                'oauthState' => $this->session->get('oauth.state'),
230
+            ],
231
+            'guest'
232
+        );
233
+    }
234 234
 
235
-	/**
236
-	 * @NoAdminRequired
237
-	 * @UseSession
238
-	 *
239
-	 * @param string $stateToken
240
-	 * @param string $clientIdentifier
241
-	 * @return Http\RedirectResponse|Response
242
-	 */
243
-	public function generateAppPassword($stateToken,
244
-										$clientIdentifier = '') {
245
-		if(!$this->isValidToken($stateToken)) {
246
-			$this->session->remove(self::stateName);
247
-			return $this->stateTokenForbiddenResponse();
248
-		}
235
+    /**
236
+     * @NoAdminRequired
237
+     * @UseSession
238
+     *
239
+     * @param string $stateToken
240
+     * @param string $clientIdentifier
241
+     * @return Http\RedirectResponse|Response
242
+     */
243
+    public function generateAppPassword($stateToken,
244
+                                        $clientIdentifier = '') {
245
+        if(!$this->isValidToken($stateToken)) {
246
+            $this->session->remove(self::stateName);
247
+            return $this->stateTokenForbiddenResponse();
248
+        }
249 249
 
250
-		$this->session->remove(self::stateName);
250
+        $this->session->remove(self::stateName);
251 251
 
252
-		try {
253
-			$sessionId = $this->session->getId();
254
-		} catch (SessionNotAvailableException $ex) {
255
-			$response = new Response();
256
-			$response->setStatus(Http::STATUS_FORBIDDEN);
257
-			return $response;
258
-		}
252
+        try {
253
+            $sessionId = $this->session->getId();
254
+        } catch (SessionNotAvailableException $ex) {
255
+            $response = new Response();
256
+            $response->setStatus(Http::STATUS_FORBIDDEN);
257
+            return $response;
258
+        }
259 259
 
260
-		try {
261
-			$sessionToken = $this->tokenProvider->getToken($sessionId);
262
-			$loginName = $sessionToken->getLoginName();
263
-			try {
264
-				$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
265
-			} catch (PasswordlessTokenException $ex) {
266
-				$password = null;
267
-			}
268
-		} catch (InvalidTokenException $ex) {
269
-			$response = new Response();
270
-			$response->setStatus(Http::STATUS_FORBIDDEN);
271
-			return $response;
272
-		}
260
+        try {
261
+            $sessionToken = $this->tokenProvider->getToken($sessionId);
262
+            $loginName = $sessionToken->getLoginName();
263
+            try {
264
+                $password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
265
+            } catch (PasswordlessTokenException $ex) {
266
+                $password = null;
267
+            }
268
+        } catch (InvalidTokenException $ex) {
269
+            $response = new Response();
270
+            $response->setStatus(Http::STATUS_FORBIDDEN);
271
+            return $response;
272
+        }
273 273
 
274
-		$clientName = $this->getClientName();
275
-		$client = false;
276
-		if($clientIdentifier !== '') {
277
-			$client = $this->clientMapper->getByIdentifier($clientIdentifier);
278
-			$clientName = $client->getName();
279
-		}
274
+        $clientName = $this->getClientName();
275
+        $client = false;
276
+        if($clientIdentifier !== '') {
277
+            $client = $this->clientMapper->getByIdentifier($clientIdentifier);
278
+            $clientName = $client->getName();
279
+        }
280 280
 
281
-		$token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
282
-		$uid = $this->userSession->getUser()->getUID();
283
-		$generatedToken = $this->tokenProvider->generateToken(
284
-			$token,
285
-			$uid,
286
-			$loginName,
287
-			$password,
288
-			$clientName,
289
-			IToken::PERMANENT_TOKEN,
290
-			IToken::DO_NOT_REMEMBER
291
-		);
281
+        $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
282
+        $uid = $this->userSession->getUser()->getUID();
283
+        $generatedToken = $this->tokenProvider->generateToken(
284
+            $token,
285
+            $uid,
286
+            $loginName,
287
+            $password,
288
+            $clientName,
289
+            IToken::PERMANENT_TOKEN,
290
+            IToken::DO_NOT_REMEMBER
291
+        );
292 292
 
293
-		if($client) {
294
-			$code = $this->random->generate(128);
295
-			$accessToken = new AccessToken();
296
-			$accessToken->setClientId($client->getId());
297
-			$accessToken->setEncryptedToken($this->crypto->encrypt($token, $code));
298
-			$accessToken->setHashedCode(hash('sha512', $code));
299
-			$accessToken->setTokenId($generatedToken->getId());
300
-			$this->accessTokenMapper->insert($accessToken);
293
+        if($client) {
294
+            $code = $this->random->generate(128);
295
+            $accessToken = new AccessToken();
296
+            $accessToken->setClientId($client->getId());
297
+            $accessToken->setEncryptedToken($this->crypto->encrypt($token, $code));
298
+            $accessToken->setHashedCode(hash('sha512', $code));
299
+            $accessToken->setTokenId($generatedToken->getId());
300
+            $this->accessTokenMapper->insert($accessToken);
301 301
 
302
-			$redirectUri = sprintf(
303
-				'%s?state=%s&code=%s',
304
-				$client->getRedirectUri(),
305
-				urlencode($this->session->get('oauth.state')),
306
-				urlencode($code)
307
-			);
308
-			$this->session->remove('oauth.state');
309
-		} else {
310
-			$serverPostfix = '';
302
+            $redirectUri = sprintf(
303
+                '%s?state=%s&code=%s',
304
+                $client->getRedirectUri(),
305
+                urlencode($this->session->get('oauth.state')),
306
+                urlencode($code)
307
+            );
308
+            $this->session->remove('oauth.state');
309
+        } else {
310
+            $serverPostfix = '';
311 311
 
312
-			if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
313
-				$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
314
-			} else if (strpos($this->request->getRequestUri(), '/login/flow') !== false) {
315
-				$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/flow'));
316
-			}
312
+            if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
313
+                $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
314
+            } else if (strpos($this->request->getRequestUri(), '/login/flow') !== false) {
315
+                $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/flow'));
316
+            }
317 317
 
318
-			$protocol = $this->request->getServerProtocol();
318
+            $protocol = $this->request->getServerProtocol();
319 319
 
320
-			if ($protocol !== "https") {
321
-				$xForwardedProto = $this->request->getHeader('X-Forwarded-Proto');
322
-				$xForwardedSSL = $this->request->getHeader('X-Forwarded-Ssl');
323
-				if ($xForwardedProto === 'https' || $xForwardedSSL === 'on') {
324
-					$protocol = 'https';
325
-				}
326
-			}
320
+            if ($protocol !== "https") {
321
+                $xForwardedProto = $this->request->getHeader('X-Forwarded-Proto');
322
+                $xForwardedSSL = $this->request->getHeader('X-Forwarded-Ssl');
323
+                if ($xForwardedProto === 'https' || $xForwardedSSL === 'on') {
324
+                    $protocol = 'https';
325
+                }
326
+            }
327 327
 
328 328
 
329
-			$serverPath = $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
330
-			$redirectUri = 'nc://login/server:' . $serverPath . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
331
-		}
329
+            $serverPath = $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
330
+            $redirectUri = 'nc://login/server:' . $serverPath . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
331
+        }
332 332
 
333
-		// Clear the token from the login here
334
-		$this->tokenProvider->invalidateToken($sessionId);
333
+        // Clear the token from the login here
334
+        $this->tokenProvider->invalidateToken($sessionId);
335 335
 
336
-		return new Http\RedirectResponse($redirectUri);
337
-	}
336
+        return new Http\RedirectResponse($redirectUri);
337
+    }
338 338
 }
Please login to merge, or discard this patch.