Completed
Push — stable10 ( c03b88...cf82aa )
by Lukas
06:45 queued 06:06
created
apps/dav/lib/Connector/Sabre/FilesPlugin.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,6 @@
 block discarded – undo
31 31
 namespace OCA\DAV\Connector\Sabre;
32 32
 
33 33
 use OC\Files\View;
34
-use OCA\DAV\Upload\FutureFile;
35 34
 use OCP\Files\ForbiddenException;
36 35
 use OCP\IPreview;
37 36
 use Sabre\DAV\Exception\Forbidden;
Please login to merge, or discard this patch.
Indentation   +383 added lines, -383 removed lines patch added patch discarded remove patch
@@ -49,388 +49,388 @@
 block discarded – undo
49 49
 
50 50
 class FilesPlugin extends ServerPlugin {
51 51
 
52
-	// namespace
53
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
54
-	const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
55
-	const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
56
-	const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
57
-	const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
58
-	const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
59
-	const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
60
-	const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
61
-	const GETETAG_PROPERTYNAME = '{DAV:}getetag';
62
-	const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
63
-	const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
64
-	const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
65
-	const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
66
-	const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
67
-	const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
68
-
69
-	/**
70
-	 * Reference to main server object
71
-	 *
72
-	 * @var \Sabre\DAV\Server
73
-	 */
74
-	private $server;
75
-
76
-	/**
77
-	 * @var Tree
78
-	 */
79
-	private $tree;
80
-
81
-	/**
82
-	 * Whether this is public webdav.
83
-	 * If true, some returned information will be stripped off.
84
-	 *
85
-	 * @var bool
86
-	 */
87
-	private $isPublic;
88
-
89
-	/**
90
-	 * @var View
91
-	 */
92
-	private $fileView;
93
-
94
-	/**
95
-	 * @var bool
96
-	 */
97
-	private $downloadAttachment;
98
-
99
-	/**
100
-	 * @var IConfig
101
-	 */
102
-	private $config;
103
-
104
-	/**
105
-	 * @var IRequest
106
-	 */
107
-	private $request;
108
-
109
-	/**
110
-	 * @var IPreview
111
-	 */
112
-	private $previewManager;
113
-
114
-	/**
115
-	 * @param Tree $tree
116
-	 * @param View $view
117
-	 * @param IConfig $config
118
-	 * @param IRequest $request
119
-	 * @param IPreview $previewManager
120
-	 * @param bool $isPublic
121
-	 * @param bool $downloadAttachment
122
-	 */
123
-	public function __construct(Tree $tree,
124
-								View $view,
125
-								IConfig $config,
126
-								IRequest $request,
127
-								IPreview $previewManager,
128
-								$isPublic = false,
129
-								$downloadAttachment = true) {
130
-		$this->tree = $tree;
131
-		$this->fileView = $view;
132
-		$this->config = $config;
133
-		$this->request = $request;
134
-		$this->isPublic = $isPublic;
135
-		$this->downloadAttachment = $downloadAttachment;
136
-		$this->previewManager = $previewManager;
137
-	}
138
-
139
-	/**
140
-	 * This initializes the plugin.
141
-	 *
142
-	 * This function is called by \Sabre\DAV\Server, after
143
-	 * addPlugin is called.
144
-	 *
145
-	 * This method should set up the required event subscriptions.
146
-	 *
147
-	 * @param \Sabre\DAV\Server $server
148
-	 * @return void
149
-	 */
150
-	public function initialize(\Sabre\DAV\Server $server) {
151
-
152
-		$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
153
-		$server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
154
-		$server->protectedProperties[] = self::FILEID_PROPERTYNAME;
155
-		$server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
156
-		$server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
157
-		$server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
158
-		$server->protectedProperties[] = self::SIZE_PROPERTYNAME;
159
-		$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
160
-		$server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
161
-		$server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
162
-		$server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
163
-		$server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
164
-		$server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
165
-
166
-		// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
167
-		$allowedProperties = ['{DAV:}getetag'];
168
-		$server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
169
-
170
-		$this->server = $server;
171
-		$this->server->on('propFind', array($this, 'handleGetProperties'));
172
-		$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
173
-		$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
174
-		$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
175
-		$this->server->on('afterMethod:GET', [$this,'httpGet']);
176
-		$this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
177
-		$this->server->on('afterResponse', function($request, ResponseInterface $response) {
178
-			$body = $response->getBody();
179
-			if (is_resource($body)) {
180
-				fclose($body);
181
-			}
182
-		});
183
-		$this->server->on('beforeMove', [$this, 'checkMove']);
184
-	}
185
-
186
-	/**
187
-	 * Plugin that checks if a move can actually be performed.
188
-	 *
189
-	 * @param string $source source path
190
-	 * @param string $destination destination path
191
-	 * @throws Forbidden
192
-	 * @throws NotFound
193
-	 */
194
-	function checkMove($source, $destination) {
195
-		$sourceNode = $this->tree->getNodeForPath($source);
196
-		if (!$sourceNode instanceof Node) {
197
-			return;
198
-		}
199
-		list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
200
-		list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
201
-
202
-		if ($sourceDir !== $destinationDir) {
203
-			$sourceNodeFileInfo = $sourceNode->getFileInfo();
204
-			if (is_null($sourceNodeFileInfo)) {
205
-				throw new NotFound($source . ' does not exist');
206
-			}
207
-
208
-			if (!$sourceNodeFileInfo->isDeletable()) {
209
-				throw new Forbidden($source . " cannot be deleted");
210
-			}
211
-		}
212
-	}
213
-
214
-	/**
215
-	 * This sets a cookie to be able to recognize the start of the download
216
-	 * the content must not be longer than 32 characters and must only contain
217
-	 * alphanumeric characters
218
-	 *
219
-	 * @param RequestInterface $request
220
-	 * @param ResponseInterface $response
221
-	 */
222
-	function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
223
-		$queryParams = $request->getQueryParameters();
224
-
225
-		/**
226
-		 * this sets a cookie to be able to recognize the start of the download
227
-		 * the content must not be longer than 32 characters and must only contain
228
-		 * alphanumeric characters
229
-		 */
230
-		if (isset($queryParams['downloadStartSecret'])) {
231
-			$token = $queryParams['downloadStartSecret'];
232
-			if (!isset($token[32])
233
-				&& preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
234
-				// FIXME: use $response->setHeader() instead
235
-				setcookie('ocDownloadStarted', $token, time() + 20, '/');
236
-			}
237
-		}
238
-	}
239
-
240
-	/**
241
-	 * Add headers to file download
242
-	 *
243
-	 * @param RequestInterface $request
244
-	 * @param ResponseInterface $response
245
-	 */
246
-	function httpGet(RequestInterface $request, ResponseInterface $response) {
247
-		// Only handle valid files
248
-		$node = $this->tree->getNodeForPath($request->getPath());
249
-		if (!($node instanceof IFile)) return;
250
-
251
-		// adds a 'Content-Disposition: attachment' header
252
-		if ($this->downloadAttachment) {
253
-			$filename = $node->getName();
254
-			if ($this->request->isUserAgent(
255
-				[
256
-					\OC\AppFramework\Http\Request::USER_AGENT_IE,
257
-					\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
258
-					\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
259
-				])) {
260
-				$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
261
-			} else {
262
-				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
263
-													 . '; filename="' . rawurlencode($filename) . '"');
264
-			}
265
-		}
266
-
267
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
268
-			//Add OC-Checksum header
269
-			/** @var $node File */
270
-			$checksum = $node->getChecksum();
271
-			if ($checksum !== null && $checksum !== '') {
272
-				$response->addHeader('OC-Checksum', $checksum);
273
-			}
274
-		}
275
-	}
276
-
277
-	/**
278
-	 * Adds all ownCloud-specific properties
279
-	 *
280
-	 * @param PropFind $propFind
281
-	 * @param \Sabre\DAV\INode $node
282
-	 * @return void
283
-	 */
284
-	public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
285
-
286
-		$httpRequest = $this->server->httpRequest;
287
-
288
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
289
-
290
-			$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
291
-				return $node->getFileId();
292
-			});
293
-
294
-			$propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
295
-				return $node->getInternalFileId();
296
-			});
297
-
298
-			$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
299
-				$perms = $node->getDavPermissions();
300
-				if ($this->isPublic) {
301
-					// remove mount information
302
-					$perms = str_replace(['S', 'M'], '', $perms);
303
-				}
304
-				return $perms;
305
-			});
306
-
307
-			$propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
308
-				return $node->getSharePermissions(
309
-					$httpRequest->getRawServerValue('PHP_AUTH_USER')
310
-				);
311
-			});
312
-
313
-			$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
314
-				return $node->getETag();
315
-			});
316
-
317
-			$propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
318
-				$owner = $node->getOwner();
319
-				return $owner->getUID();
320
-			});
321
-			$propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
322
-				$owner = $node->getOwner();
323
-				$displayName = $owner->getDisplayName();
324
-				return $displayName;
325
-			});
326
-
327
-			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
328
-				return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
329
-			});
330
-		}
331
-
332
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node
333
-			|| $node instanceof \OCA\DAV\Files\FilesHome) {
334
-			$propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
335
-				return $this->config->getSystemValue('data-fingerprint', '');
336
-			});
337
-		}
338
-
339
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
340
-			$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
341
-				/** @var $node \OCA\DAV\Connector\Sabre\File */
342
-				try {
343
-					$directDownloadUrl = $node->getDirectDownload();
344
-					if (isset($directDownloadUrl['url'])) {
345
-						return $directDownloadUrl['url'];
346
-					}
347
-				} catch (StorageNotAvailableException $e) {
348
-					return false;
349
-				} catch (ForbiddenException $e) {
350
-					return false;
351
-				}
352
-				return false;
353
-			});
354
-
355
-			$propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
356
-				$checksum = $node->getChecksum();
357
-				if ($checksum === NULL || $checksum === '') {
358
-					return null;
359
-				}
360
-
361
-				return new ChecksumList($checksum);
362
-			});
363
-
364
-		}
365
-
366
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
367
-			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
368
-				return $node->getSize();
369
-			});
370
-		}
371
-	}
372
-
373
-	/**
374
-	 * Update ownCloud-specific properties
375
-	 *
376
-	 * @param string $path
377
-	 * @param PropPatch $propPatch
378
-	 *
379
-	 * @return void
380
-	 */
381
-	public function handleUpdateProperties($path, PropPatch $propPatch) {
382
-		$propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
383
-			if (empty($time)) {
384
-				return false;
385
-			}
386
-			$node = $this->tree->getNodeForPath($path);
387
-			if (is_null($node)) {
388
-				return 404;
389
-			}
390
-			$node->touch($time);
391
-			return true;
392
-		});
393
-		$propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
394
-			if (empty($etag)) {
395
-				return false;
396
-			}
397
-			$node = $this->tree->getNodeForPath($path);
398
-			if (is_null($node)) {
399
-				return 404;
400
-			}
401
-			if ($node->setEtag($etag) !== -1) {
402
-				return true;
403
-			}
404
-			return false;
405
-		});
406
-	}
407
-
408
-	/**
409
-	 * @param string $filePath
410
-	 * @param \Sabre\DAV\INode $node
411
-	 * @throws \Sabre\DAV\Exception\BadRequest
412
-	 */
413
-	public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
414
-		// chunked upload handling
415
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
416
-			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
417
-			$info = \OC_FileChunking::decodeName($name);
418
-			if (!empty($info)) {
419
-				$filePath = $path . '/' . $info['name'];
420
-			}
421
-		}
422
-
423
-		// we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
424
-		if (!$this->server->tree->nodeExists($filePath)) {
425
-			return;
426
-		}
427
-		$node = $this->server->tree->getNodeForPath($filePath);
428
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
429
-			$fileId = $node->getFileId();
430
-			if (!is_null($fileId)) {
431
-				$this->server->httpResponse->setHeader('OC-FileId', $fileId);
432
-			}
433
-		}
434
-	}
52
+    // namespace
53
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
54
+    const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
55
+    const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
56
+    const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
57
+    const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
58
+    const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
59
+    const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
60
+    const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
61
+    const GETETAG_PROPERTYNAME = '{DAV:}getetag';
62
+    const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
63
+    const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
64
+    const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
65
+    const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
66
+    const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
67
+    const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
68
+
69
+    /**
70
+     * Reference to main server object
71
+     *
72
+     * @var \Sabre\DAV\Server
73
+     */
74
+    private $server;
75
+
76
+    /**
77
+     * @var Tree
78
+     */
79
+    private $tree;
80
+
81
+    /**
82
+     * Whether this is public webdav.
83
+     * If true, some returned information will be stripped off.
84
+     *
85
+     * @var bool
86
+     */
87
+    private $isPublic;
88
+
89
+    /**
90
+     * @var View
91
+     */
92
+    private $fileView;
93
+
94
+    /**
95
+     * @var bool
96
+     */
97
+    private $downloadAttachment;
98
+
99
+    /**
100
+     * @var IConfig
101
+     */
102
+    private $config;
103
+
104
+    /**
105
+     * @var IRequest
106
+     */
107
+    private $request;
108
+
109
+    /**
110
+     * @var IPreview
111
+     */
112
+    private $previewManager;
113
+
114
+    /**
115
+     * @param Tree $tree
116
+     * @param View $view
117
+     * @param IConfig $config
118
+     * @param IRequest $request
119
+     * @param IPreview $previewManager
120
+     * @param bool $isPublic
121
+     * @param bool $downloadAttachment
122
+     */
123
+    public function __construct(Tree $tree,
124
+                                View $view,
125
+                                IConfig $config,
126
+                                IRequest $request,
127
+                                IPreview $previewManager,
128
+                                $isPublic = false,
129
+                                $downloadAttachment = true) {
130
+        $this->tree = $tree;
131
+        $this->fileView = $view;
132
+        $this->config = $config;
133
+        $this->request = $request;
134
+        $this->isPublic = $isPublic;
135
+        $this->downloadAttachment = $downloadAttachment;
136
+        $this->previewManager = $previewManager;
137
+    }
138
+
139
+    /**
140
+     * This initializes the plugin.
141
+     *
142
+     * This function is called by \Sabre\DAV\Server, after
143
+     * addPlugin is called.
144
+     *
145
+     * This method should set up the required event subscriptions.
146
+     *
147
+     * @param \Sabre\DAV\Server $server
148
+     * @return void
149
+     */
150
+    public function initialize(\Sabre\DAV\Server $server) {
151
+
152
+        $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
153
+        $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
154
+        $server->protectedProperties[] = self::FILEID_PROPERTYNAME;
155
+        $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
156
+        $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
157
+        $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
158
+        $server->protectedProperties[] = self::SIZE_PROPERTYNAME;
159
+        $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
160
+        $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
161
+        $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
162
+        $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
163
+        $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
164
+        $server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
165
+
166
+        // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
167
+        $allowedProperties = ['{DAV:}getetag'];
168
+        $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
169
+
170
+        $this->server = $server;
171
+        $this->server->on('propFind', array($this, 'handleGetProperties'));
172
+        $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
173
+        $this->server->on('afterBind', array($this, 'sendFileIdHeader'));
174
+        $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
175
+        $this->server->on('afterMethod:GET', [$this,'httpGet']);
176
+        $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
177
+        $this->server->on('afterResponse', function($request, ResponseInterface $response) {
178
+            $body = $response->getBody();
179
+            if (is_resource($body)) {
180
+                fclose($body);
181
+            }
182
+        });
183
+        $this->server->on('beforeMove', [$this, 'checkMove']);
184
+    }
185
+
186
+    /**
187
+     * Plugin that checks if a move can actually be performed.
188
+     *
189
+     * @param string $source source path
190
+     * @param string $destination destination path
191
+     * @throws Forbidden
192
+     * @throws NotFound
193
+     */
194
+    function checkMove($source, $destination) {
195
+        $sourceNode = $this->tree->getNodeForPath($source);
196
+        if (!$sourceNode instanceof Node) {
197
+            return;
198
+        }
199
+        list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
200
+        list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
201
+
202
+        if ($sourceDir !== $destinationDir) {
203
+            $sourceNodeFileInfo = $sourceNode->getFileInfo();
204
+            if (is_null($sourceNodeFileInfo)) {
205
+                throw new NotFound($source . ' does not exist');
206
+            }
207
+
208
+            if (!$sourceNodeFileInfo->isDeletable()) {
209
+                throw new Forbidden($source . " cannot be deleted");
210
+            }
211
+        }
212
+    }
213
+
214
+    /**
215
+     * This sets a cookie to be able to recognize the start of the download
216
+     * the content must not be longer than 32 characters and must only contain
217
+     * alphanumeric characters
218
+     *
219
+     * @param RequestInterface $request
220
+     * @param ResponseInterface $response
221
+     */
222
+    function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
223
+        $queryParams = $request->getQueryParameters();
224
+
225
+        /**
226
+         * this sets a cookie to be able to recognize the start of the download
227
+         * the content must not be longer than 32 characters and must only contain
228
+         * alphanumeric characters
229
+         */
230
+        if (isset($queryParams['downloadStartSecret'])) {
231
+            $token = $queryParams['downloadStartSecret'];
232
+            if (!isset($token[32])
233
+                && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
234
+                // FIXME: use $response->setHeader() instead
235
+                setcookie('ocDownloadStarted', $token, time() + 20, '/');
236
+            }
237
+        }
238
+    }
239
+
240
+    /**
241
+     * Add headers to file download
242
+     *
243
+     * @param RequestInterface $request
244
+     * @param ResponseInterface $response
245
+     */
246
+    function httpGet(RequestInterface $request, ResponseInterface $response) {
247
+        // Only handle valid files
248
+        $node = $this->tree->getNodeForPath($request->getPath());
249
+        if (!($node instanceof IFile)) return;
250
+
251
+        // adds a 'Content-Disposition: attachment' header
252
+        if ($this->downloadAttachment) {
253
+            $filename = $node->getName();
254
+            if ($this->request->isUserAgent(
255
+                [
256
+                    \OC\AppFramework\Http\Request::USER_AGENT_IE,
257
+                    \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
258
+                    \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
259
+                ])) {
260
+                $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
261
+            } else {
262
+                $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
263
+                                                        . '; filename="' . rawurlencode($filename) . '"');
264
+            }
265
+        }
266
+
267
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
268
+            //Add OC-Checksum header
269
+            /** @var $node File */
270
+            $checksum = $node->getChecksum();
271
+            if ($checksum !== null && $checksum !== '') {
272
+                $response->addHeader('OC-Checksum', $checksum);
273
+            }
274
+        }
275
+    }
276
+
277
+    /**
278
+     * Adds all ownCloud-specific properties
279
+     *
280
+     * @param PropFind $propFind
281
+     * @param \Sabre\DAV\INode $node
282
+     * @return void
283
+     */
284
+    public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
285
+
286
+        $httpRequest = $this->server->httpRequest;
287
+
288
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
289
+
290
+            $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
291
+                return $node->getFileId();
292
+            });
293
+
294
+            $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
295
+                return $node->getInternalFileId();
296
+            });
297
+
298
+            $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
299
+                $perms = $node->getDavPermissions();
300
+                if ($this->isPublic) {
301
+                    // remove mount information
302
+                    $perms = str_replace(['S', 'M'], '', $perms);
303
+                }
304
+                return $perms;
305
+            });
306
+
307
+            $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
308
+                return $node->getSharePermissions(
309
+                    $httpRequest->getRawServerValue('PHP_AUTH_USER')
310
+                );
311
+            });
312
+
313
+            $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
314
+                return $node->getETag();
315
+            });
316
+
317
+            $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
318
+                $owner = $node->getOwner();
319
+                return $owner->getUID();
320
+            });
321
+            $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
322
+                $owner = $node->getOwner();
323
+                $displayName = $owner->getDisplayName();
324
+                return $displayName;
325
+            });
326
+
327
+            $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
328
+                return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
329
+            });
330
+        }
331
+
332
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node
333
+            || $node instanceof \OCA\DAV\Files\FilesHome) {
334
+            $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
335
+                return $this->config->getSystemValue('data-fingerprint', '');
336
+            });
337
+        }
338
+
339
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
340
+            $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
341
+                /** @var $node \OCA\DAV\Connector\Sabre\File */
342
+                try {
343
+                    $directDownloadUrl = $node->getDirectDownload();
344
+                    if (isset($directDownloadUrl['url'])) {
345
+                        return $directDownloadUrl['url'];
346
+                    }
347
+                } catch (StorageNotAvailableException $e) {
348
+                    return false;
349
+                } catch (ForbiddenException $e) {
350
+                    return false;
351
+                }
352
+                return false;
353
+            });
354
+
355
+            $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
356
+                $checksum = $node->getChecksum();
357
+                if ($checksum === NULL || $checksum === '') {
358
+                    return null;
359
+                }
360
+
361
+                return new ChecksumList($checksum);
362
+            });
363
+
364
+        }
365
+
366
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
367
+            $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
368
+                return $node->getSize();
369
+            });
370
+        }
371
+    }
372
+
373
+    /**
374
+     * Update ownCloud-specific properties
375
+     *
376
+     * @param string $path
377
+     * @param PropPatch $propPatch
378
+     *
379
+     * @return void
380
+     */
381
+    public function handleUpdateProperties($path, PropPatch $propPatch) {
382
+        $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
383
+            if (empty($time)) {
384
+                return false;
385
+            }
386
+            $node = $this->tree->getNodeForPath($path);
387
+            if (is_null($node)) {
388
+                return 404;
389
+            }
390
+            $node->touch($time);
391
+            return true;
392
+        });
393
+        $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
394
+            if (empty($etag)) {
395
+                return false;
396
+            }
397
+            $node = $this->tree->getNodeForPath($path);
398
+            if (is_null($node)) {
399
+                return 404;
400
+            }
401
+            if ($node->setEtag($etag) !== -1) {
402
+                return true;
403
+            }
404
+            return false;
405
+        });
406
+    }
407
+
408
+    /**
409
+     * @param string $filePath
410
+     * @param \Sabre\DAV\INode $node
411
+     * @throws \Sabre\DAV\Exception\BadRequest
412
+     */
413
+    public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
414
+        // chunked upload handling
415
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
416
+            list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
417
+            $info = \OC_FileChunking::decodeName($name);
418
+            if (!empty($info)) {
419
+                $filePath = $path . '/' . $info['name'];
420
+            }
421
+        }
422
+
423
+        // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
424
+        if (!$this->server->tree->nodeExists($filePath)) {
425
+            return;
426
+        }
427
+        $node = $this->server->tree->getNodeForPath($filePath);
428
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
429
+            $fileId = $node->getFileId();
430
+            if (!is_null($fileId)) {
431
+                $this->server->httpResponse->setHeader('OC-FileId', $fileId);
432
+            }
433
+        }
434
+    }
435 435
 
436 436
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
 		$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
173 173
 		$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
174 174
 		$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
175
-		$this->server->on('afterMethod:GET', [$this,'httpGet']);
175
+		$this->server->on('afterMethod:GET', [$this, 'httpGet']);
176 176
 		$this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
177 177
 		$this->server->on('afterResponse', function($request, ResponseInterface $response) {
178 178
 			$body = $response->getBody();
@@ -202,11 +202,11 @@  discard block
 block discarded – undo
202 202
 		if ($sourceDir !== $destinationDir) {
203 203
 			$sourceNodeFileInfo = $sourceNode->getFileInfo();
204 204
 			if (is_null($sourceNodeFileInfo)) {
205
-				throw new NotFound($source . ' does not exist');
205
+				throw new NotFound($source.' does not exist');
206 206
 			}
207 207
 
208 208
 			if (!$sourceNodeFileInfo->isDeletable()) {
209
-				throw new Forbidden($source . " cannot be deleted");
209
+				throw new Forbidden($source." cannot be deleted");
210 210
 			}
211 211
 		}
212 212
 	}
@@ -257,10 +257,10 @@  discard block
 block discarded – undo
257 257
 					\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
258 258
 					\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
259 259
 				])) {
260
-				$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
260
+				$response->addHeader('Content-Disposition', 'attachment; filename="'.rawurlencode($filename).'"');
261 261
 			} else {
262
-				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
263
-													 . '; filename="' . rawurlencode($filename) . '"');
262
+				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\''.rawurlencode($filename)
263
+													 . '; filename="'.rawurlencode($filename).'"');
264 264
 			}
265 265
 		}
266 266
 
@@ -324,7 +324,7 @@  discard block
 block discarded – undo
324 324
 				return $displayName;
325 325
 			});
326 326
 
327
-			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
327
+			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function() use ($node) {
328 328
 				return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
329 329
 			});
330 330
 		}
@@ -416,7 +416,7 @@  discard block
 block discarded – undo
416 416
 			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
417 417
 			$info = \OC_FileChunking::decodeName($name);
418 418
 			if (!empty($info)) {
419
-				$filePath = $path . '/' . $info['name'];
419
+				$filePath = $path.'/'.$info['name'];
420 420
 			}
421 421
 		}
422 422
 
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -246,7 +246,9 @@
 block discarded – undo
246 246
 	function httpGet(RequestInterface $request, ResponseInterface $response) {
247 247
 		// Only handle valid files
248 248
 		$node = $this->tree->getNodeForPath($request->getPath());
249
-		if (!($node instanceof IFile)) return;
249
+		if (!($node instanceof IFile)) {
250
+		    return;
251
+		}
250 252
 
251 253
 		// adds a 'Content-Disposition: attachment' header
252 254
 		if ($this->downloadAttachment) {
Please login to merge, or discard this patch.
lib/private/Memcache/APCu.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@
 block discarded – undo
65 65
 	 * Set a value in the cache if it's not already stored
66 66
 	 *
67 67
 	 * @param string $key
68
-	 * @param mixed $value
68
+	 * @param integer $value
69 69
 	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
70 70
 	 * @return bool
71 71
 	 */
Please login to merge, or discard this 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'), '4.0.6') === -1 &&
162
-				version_compare(phpversion('apcu'), '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'), '4.0.6') === -1 &&
162
+                version_compare(phpversion('apcu'), '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.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
 	use CADTrait;
38 38
 
39 39
 	public function get($key) {
40
-		$result = apcu_fetch($this->getPrefix() . $key, $success);
40
+		$result = apcu_fetch($this->getPrefix().$key, $success);
41 41
 		if (!$success) {
42 42
 			return null;
43 43
 		}
@@ -45,24 +45,24 @@  discard block
 block discarded – undo
45 45
 	}
46 46
 
47 47
 	public function set($key, $value, $ttl = 0) {
48
-		return apcu_store($this->getPrefix() . $key, $value, $ttl);
48
+		return apcu_store($this->getPrefix().$key, $value, $ttl);
49 49
 	}
50 50
 
51 51
 	public function hasKey($key) {
52
-		return apcu_exists($this->getPrefix() . $key);
52
+		return apcu_exists($this->getPrefix().$key);
53 53
 	}
54 54
 
55 55
 	public function remove($key) {
56
-		return apcu_delete($this->getPrefix() . $key);
56
+		return apcu_delete($this->getPrefix().$key);
57 57
 	}
58 58
 
59 59
 	public function clear($prefix = '') {
60
-		$ns = $this->getPrefix() . $prefix;
60
+		$ns = $this->getPrefix().$prefix;
61 61
 		$ns = preg_quote($ns, '/');
62
-		if(class_exists('\APCIterator')) {
63
-			$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
62
+		if (class_exists('\APCIterator')) {
63
+			$iter = new \APCIterator('user', '/^'.$ns.'/', APC_ITER_KEY);
64 64
 		} else {
65
-			$iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
65
+			$iter = new \APCUIterator('/^'.$ns.'/', APC_ITER_KEY);
66 66
 		}
67 67
 		return apcu_delete($iter);
68 68
 	}
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 	 * @return bool
77 77
 	 */
78 78
 	public function add($key, $value, $ttl = 0) {
79
-		return apcu_add($this->getPrefix() . $key, $value, $ttl);
79
+		return apcu_add($this->getPrefix().$key, $value, $ttl);
80 80
 	}
81 81
 
82 82
 	/**
@@ -100,8 +100,8 @@  discard block
 block discarded – undo
100 100
 		 * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
101 101
 		 * for details
102 102
 		 */
103
-		return apcu_exists($this->getPrefix() . $key)
104
-			? apcu_inc($this->getPrefix() . $key, $step)
103
+		return apcu_exists($this->getPrefix().$key)
104
+			? apcu_inc($this->getPrefix().$key, $step)
105 105
 			: false;
106 106
 	}
107 107
 
@@ -125,8 +125,8 @@  discard block
 block discarded – undo
125 125
 		 * see https://github.com/krakjoe/apcu/issues/183#issuecomment-244038221
126 126
 		 * for details
127 127
 		 */
128
-		return apcu_exists($this->getPrefix() . $key)
129
-			? apcu_dec($this->getPrefix() . $key, $step)
128
+		return apcu_exists($this->getPrefix().$key)
129
+			? apcu_dec($this->getPrefix().$key, $step)
130 130
 			: false;
131 131
 	}
132 132
 
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
 	public function cas($key, $old, $new) {
142 142
 		// apc only does cas for ints
143 143
 		if (is_int($old) and is_int($new)) {
144
-			return apcu_cas($this->getPrefix() . $key, $old, $new);
144
+			return apcu_cas($this->getPrefix().$key, $old, $new);
145 145
 		} else {
146 146
 			return $this->casEmulated($key, $old, $new);
147 147
 		}
Please login to merge, or discard this patch.
lib/private/Memcache/ArrayCache.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@
 block discarded – undo
65 65
 	 * Set a value in the cache if it's not already stored
66 66
 	 *
67 67
 	 * @param string $key
68
-	 * @param mixed $value
68
+	 * @param integer $value
69 69
 	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
70 70
 	 * @return bool
71 71
 	 */
Please login to merge, or discard this patch.
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -27,133 +27,133 @@
 block discarded – undo
27 27
 use OCP\IMemcache;
28 28
 
29 29
 class ArrayCache extends Cache implements IMemcache {
30
-	/** @var array Array with the cached data */
31
-	protected $cachedData = array();
30
+    /** @var array Array with the cached data */
31
+    protected $cachedData = array();
32 32
 
33
-	use CADTrait;
33
+    use CADTrait;
34 34
 
35
-	/**
36
-	 * {@inheritDoc}
37
-	 */
38
-	public function get($key) {
39
-		if ($this->hasKey($key)) {
40
-			return $this->cachedData[$key];
41
-		}
42
-		return null;
43
-	}
35
+    /**
36
+     * {@inheritDoc}
37
+     */
38
+    public function get($key) {
39
+        if ($this->hasKey($key)) {
40
+            return $this->cachedData[$key];
41
+        }
42
+        return null;
43
+    }
44 44
 
45
-	/**
46
-	 * {@inheritDoc}
47
-	 */
48
-	public function set($key, $value, $ttl = 0) {
49
-		$this->cachedData[$key] = $value;
50
-		return true;
51
-	}
45
+    /**
46
+     * {@inheritDoc}
47
+     */
48
+    public function set($key, $value, $ttl = 0) {
49
+        $this->cachedData[$key] = $value;
50
+        return true;
51
+    }
52 52
 
53
-	/**
54
-	 * {@inheritDoc}
55
-	 */
56
-	public function hasKey($key) {
57
-		return isset($this->cachedData[$key]);
58
-	}
53
+    /**
54
+     * {@inheritDoc}
55
+     */
56
+    public function hasKey($key) {
57
+        return isset($this->cachedData[$key]);
58
+    }
59 59
 
60
-	/**
61
-	 * {@inheritDoc}
62
-	 */
63
-	public function remove($key) {
64
-		unset($this->cachedData[$key]);
65
-		return true;
66
-	}
60
+    /**
61
+     * {@inheritDoc}
62
+     */
63
+    public function remove($key) {
64
+        unset($this->cachedData[$key]);
65
+        return true;
66
+    }
67 67
 
68
-	/**
69
-	 * {@inheritDoc}
70
-	 */
71
-	public function clear($prefix = '') {
72
-		if ($prefix === '') {
73
-			$this->cachedData = [];
74
-			return true;
75
-		}
68
+    /**
69
+     * {@inheritDoc}
70
+     */
71
+    public function clear($prefix = '') {
72
+        if ($prefix === '') {
73
+            $this->cachedData = [];
74
+            return true;
75
+        }
76 76
 
77
-		foreach ($this->cachedData as $key => $value) {
78
-			if (strpos($key, $prefix) === 0) {
79
-				$this->remove($key);
80
-			}
81
-		}
82
-		return true;
83
-	}
77
+        foreach ($this->cachedData as $key => $value) {
78
+            if (strpos($key, $prefix) === 0) {
79
+                $this->remove($key);
80
+            }
81
+        }
82
+        return true;
83
+    }
84 84
 
85
-	/**
86
-	 * Set a value in the cache if it's not already stored
87
-	 *
88
-	 * @param string $key
89
-	 * @param mixed $value
90
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
91
-	 * @return bool
92
-	 */
93
-	public function add($key, $value, $ttl = 0) {
94
-		// since this cache is not shared race conditions aren't an issue
95
-		if ($this->hasKey($key)) {
96
-			return false;
97
-		} else {
98
-			return $this->set($key, $value, $ttl);
99
-		}
100
-	}
85
+    /**
86
+     * Set a value in the cache if it's not already stored
87
+     *
88
+     * @param string $key
89
+     * @param mixed $value
90
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
91
+     * @return bool
92
+     */
93
+    public function add($key, $value, $ttl = 0) {
94
+        // since this cache is not shared race conditions aren't an issue
95
+        if ($this->hasKey($key)) {
96
+            return false;
97
+        } else {
98
+            return $this->set($key, $value, $ttl);
99
+        }
100
+    }
101 101
 
102
-	/**
103
-	 * Increase a stored number
104
-	 *
105
-	 * @param string $key
106
-	 * @param int $step
107
-	 * @return int | bool
108
-	 */
109
-	public function inc($key, $step = 1) {
110
-		$oldValue = $this->get($key);
111
-		if (is_int($oldValue)) {
112
-			$this->set($key, $oldValue + $step);
113
-			return $oldValue + $step;
114
-		} else {
115
-			$success = $this->add($key, $step);
116
-			return ($success) ? $step : false;
117
-		}
118
-	}
102
+    /**
103
+     * Increase a stored number
104
+     *
105
+     * @param string $key
106
+     * @param int $step
107
+     * @return int | bool
108
+     */
109
+    public function inc($key, $step = 1) {
110
+        $oldValue = $this->get($key);
111
+        if (is_int($oldValue)) {
112
+            $this->set($key, $oldValue + $step);
113
+            return $oldValue + $step;
114
+        } else {
115
+            $success = $this->add($key, $step);
116
+            return ($success) ? $step : false;
117
+        }
118
+    }
119 119
 
120
-	/**
121
-	 * Decrease a stored number
122
-	 *
123
-	 * @param string $key
124
-	 * @param int $step
125
-	 * @return int | bool
126
-	 */
127
-	public function dec($key, $step = 1) {
128
-		$oldValue = $this->get($key);
129
-		if (is_int($oldValue)) {
130
-			$this->set($key, $oldValue - $step);
131
-			return $oldValue - $step;
132
-		} else {
133
-			return false;
134
-		}
135
-	}
120
+    /**
121
+     * Decrease a stored number
122
+     *
123
+     * @param string $key
124
+     * @param int $step
125
+     * @return int | bool
126
+     */
127
+    public function dec($key, $step = 1) {
128
+        $oldValue = $this->get($key);
129
+        if (is_int($oldValue)) {
130
+            $this->set($key, $oldValue - $step);
131
+            return $oldValue - $step;
132
+        } else {
133
+            return false;
134
+        }
135
+    }
136 136
 
137
-	/**
138
-	 * Compare and set
139
-	 *
140
-	 * @param string $key
141
-	 * @param mixed $old
142
-	 * @param mixed $new
143
-	 * @return bool
144
-	 */
145
-	public function cas($key, $old, $new) {
146
-		if ($this->get($key) === $old) {
147
-			return $this->set($key, $new);
148
-		} else {
149
-			return false;
150
-		}
151
-	}
137
+    /**
138
+     * Compare and set
139
+     *
140
+     * @param string $key
141
+     * @param mixed $old
142
+     * @param mixed $new
143
+     * @return bool
144
+     */
145
+    public function cas($key, $old, $new) {
146
+        if ($this->get($key) === $old) {
147
+            return $this->set($key, $new);
148
+        } else {
149
+            return false;
150
+        }
151
+    }
152 152
 
153
-	/**
154
-	 * {@inheritDoc}
155
-	 */
156
-	static public function isAvailable() {
157
-		return true;
158
-	}
153
+    /**
154
+     * {@inheritDoc}
155
+     */
156
+    static public function isAvailable() {
157
+        return true;
158
+    }
159 159
 }
Please login to merge, or discard this patch.
lib/private/User/Session.php 3 patches
Doc Comments   +4 added lines, -1 removed lines patch added patch discarded remove patch
@@ -311,7 +311,7 @@  discard block
 block discarded – undo
311 311
 	 * @param OC\Security\Bruteforce\Throttler $throttler
312 312
 	 * @throws LoginException
313 313
 	 * @throws PasswordLoginForbiddenException
314
-	 * @return boolean
314
+	 * @return boolean|null
315 315
 	 */
316 316
 	public function logClientIn($user,
317 317
 								$password,
@@ -361,6 +361,9 @@  discard block
 block discarded – undo
361 361
 		return $this->config->getSystemValue('token_auth_enforced', false);
362 362
 	}
363 363
 
364
+	/**
365
+	 * @param string $username
366
+	 */
364 367
 	protected function isTwoFactorEnforced($username) {
365 368
 		Util::emitHook(
366 369
 			'\OCA\Files_Sharing\API\Server2Server',
Please login to merge, or discard this patch.
Indentation   +708 added lines, -708 removed lines patch added patch discarded remove patch
@@ -71,714 +71,714 @@
 block discarded – undo
71 71
  */
72 72
 class Session implements IUserSession, Emitter {
73 73
 
74
-	/** @var IUserManager $manager */
75
-	private $manager;
76
-
77
-	/** @var ISession $session */
78
-	private $session;
79
-
80
-	/** @var ITimeFactory */
81
-	private $timeFacory;
82
-
83
-	/** @var IProvider */
84
-	private $tokenProvider;
85
-
86
-	/** @var IConfig */
87
-	private $config;
88
-
89
-	/** @var User $activeUser */
90
-	protected $activeUser;
91
-
92
-	/**
93
-	 * @param IUserManager $manager
94
-	 * @param ISession $session
95
-	 * @param ITimeFactory $timeFacory
96
-	 * @param IProvider $tokenProvider
97
-	 * @param IConfig $config
98
-	 */
99
-	public function __construct(IUserManager $manager,
100
-								ISession $session,
101
-								ITimeFactory $timeFacory,
102
-								$tokenProvider,
103
-								IConfig $config) {
104
-		$this->manager = $manager;
105
-		$this->session = $session;
106
-		$this->timeFacory = $timeFacory;
107
-		$this->tokenProvider = $tokenProvider;
108
-		$this->config = $config;
109
-	}
110
-
111
-	/**
112
-	 * @param IProvider $provider
113
-	 */
114
-	public function setTokenProvider(IProvider $provider) {
115
-		$this->tokenProvider = $provider;
116
-	}
117
-
118
-	/**
119
-	 * @param string $scope
120
-	 * @param string $method
121
-	 * @param callable $callback
122
-	 */
123
-	public function listen($scope, $method, callable $callback) {
124
-		$this->manager->listen($scope, $method, $callback);
125
-	}
126
-
127
-	/**
128
-	 * @param string $scope optional
129
-	 * @param string $method optional
130
-	 * @param callable $callback optional
131
-	 */
132
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
133
-		$this->manager->removeListener($scope, $method, $callback);
134
-	}
135
-
136
-	/**
137
-	 * get the manager object
138
-	 *
139
-	 * @return Manager
140
-	 */
141
-	public function getManager() {
142
-		return $this->manager;
143
-	}
144
-
145
-	/**
146
-	 * get the session object
147
-	 *
148
-	 * @return ISession
149
-	 */
150
-	public function getSession() {
151
-		return $this->session;
152
-	}
153
-
154
-	/**
155
-	 * set the session object
156
-	 *
157
-	 * @param ISession $session
158
-	 */
159
-	public function setSession(ISession $session) {
160
-		if ($this->session instanceof ISession) {
161
-			$this->session->close();
162
-		}
163
-		$this->session = $session;
164
-		$this->activeUser = null;
165
-	}
166
-
167
-	/**
168
-	 * set the currently active user
169
-	 *
170
-	 * @param User|null $user
171
-	 */
172
-	public function setUser($user) {
173
-		if (is_null($user)) {
174
-			$this->session->remove('user_id');
175
-		} else {
176
-			$this->session->set('user_id', $user->getUID());
177
-		}
178
-		$this->activeUser = $user;
179
-	}
180
-
181
-	/**
182
-	 * get the current active user
183
-	 *
184
-	 * @return IUser|null Current user, otherwise null
185
-	 */
186
-	public function getUser() {
187
-		// FIXME: This is a quick'n dirty work-around for the incognito mode as
188
-		// described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
189
-		if (OC_User::isIncognitoMode()) {
190
-			return null;
191
-		}
192
-		if (is_null($this->activeUser)) {
193
-			$uid = $this->session->get('user_id');
194
-			if (is_null($uid)) {
195
-				return null;
196
-			}
197
-			$this->activeUser = $this->manager->get($uid);
198
-			if (is_null($this->activeUser)) {
199
-				return null;
200
-			}
201
-			$this->validateSession();
202
-		}
203
-		return $this->activeUser;
204
-	}
205
-
206
-	/**
207
-	 * Validate whether the current session is valid
208
-	 *
209
-	 * - For token-authenticated clients, the token validity is checked
210
-	 * - For browsers, the session token validity is checked
211
-	 */
212
-	protected function validateSession() {
213
-		$token = null;
214
-		$appPassword = $this->session->get('app_password');
215
-
216
-		if (is_null($appPassword)) {
217
-			try {
218
-				$token = $this->session->getId();
219
-			} catch (SessionNotAvailableException $ex) {
220
-				return;
221
-			}
222
-		} else {
223
-			$token = $appPassword;
224
-		}
225
-
226
-		if (!$this->validateToken($token)) {
227
-			// Session was invalidated
228
-			$this->logout();
229
-		}
230
-	}
231
-
232
-	/**
233
-	 * Checks whether the user is logged in
234
-	 *
235
-	 * @return bool if logged in
236
-	 */
237
-	public function isLoggedIn() {
238
-		$user = $this->getUser();
239
-		if (is_null($user)) {
240
-			return false;
241
-		}
242
-
243
-		return $user->isEnabled();
244
-	}
245
-
246
-	/**
247
-	 * set the login name
248
-	 *
249
-	 * @param string|null $loginName for the logged in user
250
-	 */
251
-	public function setLoginName($loginName) {
252
-		if (is_null($loginName)) {
253
-			$this->session->remove('loginname');
254
-		} else {
255
-			$this->session->set('loginname', $loginName);
256
-		}
257
-	}
258
-
259
-	/**
260
-	 * get the login name of the current user
261
-	 *
262
-	 * @return string
263
-	 */
264
-	public function getLoginName() {
265
-		if ($this->activeUser) {
266
-			return $this->session->get('loginname');
267
-		} else {
268
-			$uid = $this->session->get('user_id');
269
-			if ($uid) {
270
-				$this->activeUser = $this->manager->get($uid);
271
-				return $this->session->get('loginname');
272
-			} else {
273
-				return null;
274
-			}
275
-		}
276
-	}
277
-
278
-	/**
279
-	 * try to log in with the provided credentials
280
-	 *
281
-	 * @param string $uid
282
-	 * @param string $password
283
-	 * @return boolean|null
284
-	 * @throws LoginException
285
-	 */
286
-	public function login($uid, $password) {
287
-		$this->session->regenerateId();
288
-		if ($this->validateToken($password, $uid)) {
289
-			return $this->loginWithToken($password);
290
-		} else {
291
-			return $this->loginWithPassword($uid, $password);
292
-		}
293
-		return false;
294
-	}
295
-
296
-	/**
297
-	 * Tries to log in a client
298
-	 *
299
-	 * Checks token auth enforced
300
-	 * Checks 2FA enabled
301
-	 *
302
-	 * @param string $user
303
-	 * @param string $password
304
-	 * @param IRequest $request
305
-	 * @param OC\Security\Bruteforce\Throttler $throttler
306
-	 * @throws LoginException
307
-	 * @throws PasswordLoginForbiddenException
308
-	 * @return boolean
309
-	 */
310
-	public function logClientIn($user,
311
-								$password,
312
-								IRequest $request,
313
-								OC\Security\Bruteforce\Throttler $throttler) {
314
-		$currentDelay = $throttler->getDelay($request->getRemoteAddress());
315
-		$throttler->sleepDelay($request->getRemoteAddress());
316
-
317
-		$isTokenPassword = $this->isTokenPassword($password);
318
-		if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
319
-			throw new PasswordLoginForbiddenException();
320
-		}
321
-		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
322
-			throw new PasswordLoginForbiddenException();
323
-		}
324
-		if (!$this->login($user, $password) ) {
325
-			$users = $this->manager->getByEmail($user);
326
-			if (count($users) === 1) {
327
-				return $this->login($users[0]->getUID(), $password);
328
-			}
329
-
330
-			$throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
331
-			if($currentDelay === 0) {
332
-				$throttler->sleepDelay($request->getRemoteAddress());
333
-			}
334
-			return false;
335
-		}
336
-
337
-		if ($isTokenPassword) {
338
-			$this->session->set('app_password', $password);
339
-		} else if($this->supportsCookies($request)) {
340
-			// Password login, but cookies supported -> create (browser) session token
341
-			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
342
-		}
343
-
344
-		return true;
345
-	}
346
-
347
-	protected function supportsCookies(IRequest $request) {
348
-		if (!is_null($request->getCookie('cookie_test'))) {
349
-			return true;
350
-		}
351
-		setcookie('cookie_test', 'test', $this->timeFacory->getTime() + 3600);
352
-		return false;
353
-	}
354
-
355
-	private function isTokenAuthEnforced() {
356
-		return $this->config->getSystemValue('token_auth_enforced', false);
357
-	}
358
-
359
-	protected function isTwoFactorEnforced($username) {
360
-		Util::emitHook(
361
-			'\OCA\Files_Sharing\API\Server2Server',
362
-			'preLoginNameUsedAsUserName',
363
-			array('uid' => &$username)
364
-		);
365
-		$user = $this->manager->get($username);
366
-		if (is_null($user)) {
367
-			$users = $this->manager->getByEmail($username);
368
-			if (count($users) !== 1) {
369
-				return true;
370
-			}
371
-			$user = $users[0];
372
-		}
373
-		// DI not possible due to cyclic dependencies :'-/
374
-		return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
375
-	}
376
-
377
-	/**
378
-	 * Check if the given 'password' is actually a device token
379
-	 *
380
-	 * @param string $password
381
-	 * @return boolean
382
-	 */
383
-	public function isTokenPassword($password) {
384
-		try {
385
-			$this->tokenProvider->getToken($password);
386
-			return true;
387
-		} catch (InvalidTokenException $ex) {
388
-			return false;
389
-		}
390
-	}
391
-
392
-	protected function prepareUserLogin() {
393
-		// TODO: mock/inject/use non-static
394
-		// Refresh the token
395
-		\OC::$server->getCsrfTokenManager()->refreshToken();
396
-		//we need to pass the user name, which may differ from login name
397
-		$user = $this->getUser()->getUID();
398
-		OC_Util::setupFS($user);
399
-		//trigger creation of user home and /files folder
400
-		\OC::$server->getUserFolder($user);
401
-	}
402
-
403
-	/**
404
-	 * Tries to login the user with HTTP Basic Authentication
405
-	 *
406
-	 * @todo do not allow basic auth if the user is 2FA enforced
407
-	 * @param IRequest $request
408
-	 * @return boolean if the login was successful
409
-	 */
410
-	public function tryBasicAuthLogin(IRequest $request,
411
-									  OC\Security\Bruteforce\Throttler $throttler) {
412
-		if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
413
-			try {
414
-				if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
415
-					/**
416
-					 * Add DAV authenticated. This should in an ideal world not be
417
-					 * necessary but the iOS App reads cookies from anywhere instead
418
-					 * only the DAV endpoint.
419
-					 * This makes sure that the cookies will be valid for the whole scope
420
-					 * @see https://github.com/owncloud/core/issues/22893
421
-					 */
422
-					$this->session->set(
423
-						Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
424
-					);
425
-					return true;
426
-				}
427
-			} catch (PasswordLoginForbiddenException $ex) {
428
-				// Nothing to do
429
-			}
430
-		}
431
-		return false;
432
-	}
433
-
434
-	/**
435
-	 * Log an user in via login name and password
436
-	 *
437
-	 * @param string $uid
438
-	 * @param string $password
439
-	 * @return boolean
440
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
441
-	 */
442
-	private function loginWithPassword($uid, $password) {
443
-		$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
444
-		$user = $this->manager->checkPassword($uid, $password);
445
-		if ($user === false) {
446
-			// Password check failed
447
-			return false;
448
-		}
449
-
450
-		if ($user->isEnabled()) {
451
-			$this->setUser($user);
452
-			$this->setLoginName($uid);
453
-			$this->manager->emit('\OC\User', 'postLogin', array($user, $password));
454
-			if ($this->isLoggedIn()) {
455
-				$this->prepareUserLogin();
456
-				return true;
457
-			} else {
458
-				// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
459
-				$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
460
-				throw new LoginException($message);
461
-			}
462
-		} else {
463
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
464
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
465
-			throw new LoginException($message);
466
-		}
467
-		return false;
468
-	}
469
-
470
-	/**
471
-	 * Log an user in with a given token (id)
472
-	 *
473
-	 * @param string $token
474
-	 * @return boolean
475
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
476
-	 */
477
-	private function loginWithToken($token) {
478
-		try {
479
-			$dbToken = $this->tokenProvider->getToken($token);
480
-		} catch (InvalidTokenException $ex) {
481
-			return false;
482
-		}
483
-		$uid = $dbToken->getUID();
484
-
485
-		// When logging in with token, the password must be decrypted first before passing to login hook
486
-		$password = '';
487
-		try {
488
-			$password = $this->tokenProvider->getPassword($dbToken, $token);
489
-		} catch (PasswordlessTokenException $ex) {
490
-			// Ignore and use empty string instead
491
-		}
492
-
493
-		$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
494
-
495
-		$user = $this->manager->get($uid);
496
-		if (is_null($user)) {
497
-			// user does not exist
498
-			return false;
499
-		}
500
-		if (!$user->isEnabled()) {
501
-			// disabled users can not log in
502
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
503
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
504
-			throw new LoginException($message);
505
-		}
506
-
507
-		//login
508
-		$this->setUser($user);
509
-		$this->setLoginName($dbToken->getLoginName());
510
-		$this->manager->emit('\OC\User', 'postLogin', array($user, $password));
511
-
512
-		if ($this->isLoggedIn()) {
513
-			$this->prepareUserLogin();
514
-		} else {
515
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
516
-			$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
517
-			throw new LoginException($message);
518
-		}
519
-
520
-		return true;
521
-	}
522
-
523
-	/**
524
-	 * Create a new session token for the given user credentials
525
-	 *
526
-	 * @param IRequest $request
527
-	 * @param string $uid user UID
528
-	 * @param string $loginName login name
529
-	 * @param string $password
530
-	 * @return boolean
531
-	 */
532
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null) {
533
-		if (is_null($this->manager->get($uid))) {
534
-			// User does not exist
535
-			return false;
536
-		}
537
-		$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
538
-		try {
539
-			$sessionId = $this->session->getId();
540
-			$pwd = $this->getPassword($password);
541
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name);
542
-			return true;
543
-		} catch (SessionNotAvailableException $ex) {
544
-			// This can happen with OCC, where a memory session is used
545
-			// if a memory session is used, we shouldn't create a session token anyway
546
-			return false;
547
-		}
548
-	}
549
-
550
-	/**
551
-	 * Checks if the given password is a token.
552
-	 * If yes, the password is extracted from the token.
553
-	 * If no, the same password is returned.
554
-	 *
555
-	 * @param string $password either the login password or a device token
556
-	 * @return string|null the password or null if none was set in the token
557
-	 */
558
-	private function getPassword($password) {
559
-		if (is_null($password)) {
560
-			// This is surely no token ;-)
561
-			return null;
562
-		}
563
-		try {
564
-			$token = $this->tokenProvider->getToken($password);
565
-			try {
566
-				return $this->tokenProvider->getPassword($token, $password);
567
-			} catch (PasswordlessTokenException $ex) {
568
-				return null;
569
-			}
570
-		} catch (InvalidTokenException $ex) {
571
-			return $password;
572
-		}
573
-	}
574
-
575
-	/**
576
-	 * @param IToken $dbToken
577
-	 * @param string $token
578
-	 * @return boolean
579
-	 */
580
-	private function checkTokenCredentials(IToken $dbToken, $token) {
581
-		// Check whether login credentials are still valid and the user was not disabled
582
-		// This check is performed each 5 minutes
583
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
584
-		$now = $this->timeFacory->getTime();
585
-		if ($lastCheck > ($now - 60 * 5)) {
586
-			// Checked performed recently, nothing to do now
587
-			return true;
588
-		}
589
-
590
-		try {
591
-			$pwd = $this->tokenProvider->getPassword($dbToken, $token);
592
-		} catch (InvalidTokenException $ex) {
593
-			// An invalid token password was used -> log user out
594
-			return false;
595
-		} catch (PasswordlessTokenException $ex) {
596
-			// Token has no password
597
-
598
-			if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
599
-				$this->tokenProvider->invalidateToken($token);
600
-				return false;
601
-			}
602
-
603
-			$dbToken->setLastCheck($now);
604
-			$this->tokenProvider->updateToken($dbToken);
605
-			return true;
606
-		}
607
-
608
-		if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false
609
-			|| (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) {
610
-			$this->tokenProvider->invalidateToken($token);
611
-			// Password has changed or user was disabled -> log user out
612
-			return false;
613
-		}
614
-		$dbToken->setLastCheck($now);
615
-		$this->tokenProvider->updateToken($dbToken);
616
-		return true;
617
-	}
618
-
619
-	/**
620
-	 * Check if the given token exists and performs password/user-enabled checks
621
-	 *
622
-	 * Invalidates the token if checks fail
623
-	 *
624
-	 * @param string $token
625
-	 * @param string $user login name
626
-	 * @return boolean
627
-	 */
628
-	private function validateToken($token, $user = null) {
629
-		try {
630
-			$dbToken = $this->tokenProvider->getToken($token);
631
-		} catch (InvalidTokenException $ex) {
632
-			return false;
633
-		}
634
-
635
-		// Check if login names match
636
-		if (!is_null($user) && $dbToken->getLoginName() !== $user) {
637
-			// TODO: this makes it imposssible to use different login names on browser and client
638
-			// e.g. login by e-mail '[email protected]' on browser for generating the token will not
639
-			//      allow to use the client token with the login name 'user'.
640
-			return false;
641
-		}
642
-
643
-		if (!$this->checkTokenCredentials($dbToken, $token)) {
644
-			return false;
645
-		}
646
-
647
-		$this->tokenProvider->updateTokenActivity($dbToken);
648
-
649
-		return true;
650
-	}
651
-
652
-	/**
653
-	 * Tries to login the user with auth token header
654
-	 *
655
-	 * @todo check remember me cookie
656
-	 * @return boolean
657
-	 */
658
-	public function tryTokenLogin(IRequest $request) {
659
-		$authHeader = $request->getHeader('Authorization');
660
-		if (strpos($authHeader, 'token ') === false) {
661
-			// No auth header, let's try session id
662
-			try {
663
-				$token = $this->session->getId();
664
-			} catch (SessionNotAvailableException $ex) {
665
-				return false;
666
-			}
667
-		} else {
668
-			$token = substr($authHeader, 6);
669
-		}
670
-
671
-		if (!$this->loginWithToken($token)) {
672
-			return false;
673
-		}
674
-		if(!$this->validateToken($token)) {
675
-			return false;
676
-		}
677
-		return true;
678
-	}
679
-
680
-	/**
681
-	 * perform login using the magic cookie (remember login)
682
-	 *
683
-	 * @param string $uid the username
684
-	 * @param string $currentToken
685
-	 * @return bool
686
-	 */
687
-	public function loginWithCookie($uid, $currentToken) {
688
-		$this->session->regenerateId();
689
-		$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
690
-		$user = $this->manager->get($uid);
691
-		if (is_null($user)) {
692
-			// user does not exist
693
-			return false;
694
-		}
695
-
696
-		// get stored tokens
697
-		$tokens = OC::$server->getConfig()->getUserKeys($uid, 'login_token');
698
-		// test cookies token against stored tokens
699
-		if (!in_array($currentToken, $tokens, true)) {
700
-			return false;
701
-		}
702
-		// replace successfully used token with a new one
703
-		OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken);
704
-		$newToken = OC::$server->getSecureRandom()->generate(32);
705
-		OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time());
706
-		$this->setMagicInCookie($user->getUID(), $newToken);
707
-
708
-		//login
709
-		$this->setUser($user);
710
-		$this->manager->emit('\OC\User', 'postRememberedLogin', array($user));
711
-		return true;
712
-	}
713
-
714
-	/**
715
-	 * logout the user from the session
716
-	 */
717
-	public function logout() {
718
-		$this->manager->emit('\OC\User', 'logout');
719
-		$user = $this->getUser();
720
-		if (!is_null($user)) {
721
-			try {
722
-				$this->tokenProvider->invalidateToken($this->session->getId());
723
-			} catch (SessionNotAvailableException $ex) {
74
+    /** @var IUserManager $manager */
75
+    private $manager;
76
+
77
+    /** @var ISession $session */
78
+    private $session;
79
+
80
+    /** @var ITimeFactory */
81
+    private $timeFacory;
82
+
83
+    /** @var IProvider */
84
+    private $tokenProvider;
85
+
86
+    /** @var IConfig */
87
+    private $config;
88
+
89
+    /** @var User $activeUser */
90
+    protected $activeUser;
91
+
92
+    /**
93
+     * @param IUserManager $manager
94
+     * @param ISession $session
95
+     * @param ITimeFactory $timeFacory
96
+     * @param IProvider $tokenProvider
97
+     * @param IConfig $config
98
+     */
99
+    public function __construct(IUserManager $manager,
100
+                                ISession $session,
101
+                                ITimeFactory $timeFacory,
102
+                                $tokenProvider,
103
+                                IConfig $config) {
104
+        $this->manager = $manager;
105
+        $this->session = $session;
106
+        $this->timeFacory = $timeFacory;
107
+        $this->tokenProvider = $tokenProvider;
108
+        $this->config = $config;
109
+    }
110
+
111
+    /**
112
+     * @param IProvider $provider
113
+     */
114
+    public function setTokenProvider(IProvider $provider) {
115
+        $this->tokenProvider = $provider;
116
+    }
117
+
118
+    /**
119
+     * @param string $scope
120
+     * @param string $method
121
+     * @param callable $callback
122
+     */
123
+    public function listen($scope, $method, callable $callback) {
124
+        $this->manager->listen($scope, $method, $callback);
125
+    }
126
+
127
+    /**
128
+     * @param string $scope optional
129
+     * @param string $method optional
130
+     * @param callable $callback optional
131
+     */
132
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
133
+        $this->manager->removeListener($scope, $method, $callback);
134
+    }
135
+
136
+    /**
137
+     * get the manager object
138
+     *
139
+     * @return Manager
140
+     */
141
+    public function getManager() {
142
+        return $this->manager;
143
+    }
144
+
145
+    /**
146
+     * get the session object
147
+     *
148
+     * @return ISession
149
+     */
150
+    public function getSession() {
151
+        return $this->session;
152
+    }
153
+
154
+    /**
155
+     * set the session object
156
+     *
157
+     * @param ISession $session
158
+     */
159
+    public function setSession(ISession $session) {
160
+        if ($this->session instanceof ISession) {
161
+            $this->session->close();
162
+        }
163
+        $this->session = $session;
164
+        $this->activeUser = null;
165
+    }
166
+
167
+    /**
168
+     * set the currently active user
169
+     *
170
+     * @param User|null $user
171
+     */
172
+    public function setUser($user) {
173
+        if (is_null($user)) {
174
+            $this->session->remove('user_id');
175
+        } else {
176
+            $this->session->set('user_id', $user->getUID());
177
+        }
178
+        $this->activeUser = $user;
179
+    }
180
+
181
+    /**
182
+     * get the current active user
183
+     *
184
+     * @return IUser|null Current user, otherwise null
185
+     */
186
+    public function getUser() {
187
+        // FIXME: This is a quick'n dirty work-around for the incognito mode as
188
+        // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
189
+        if (OC_User::isIncognitoMode()) {
190
+            return null;
191
+        }
192
+        if (is_null($this->activeUser)) {
193
+            $uid = $this->session->get('user_id');
194
+            if (is_null($uid)) {
195
+                return null;
196
+            }
197
+            $this->activeUser = $this->manager->get($uid);
198
+            if (is_null($this->activeUser)) {
199
+                return null;
200
+            }
201
+            $this->validateSession();
202
+        }
203
+        return $this->activeUser;
204
+    }
205
+
206
+    /**
207
+     * Validate whether the current session is valid
208
+     *
209
+     * - For token-authenticated clients, the token validity is checked
210
+     * - For browsers, the session token validity is checked
211
+     */
212
+    protected function validateSession() {
213
+        $token = null;
214
+        $appPassword = $this->session->get('app_password');
215
+
216
+        if (is_null($appPassword)) {
217
+            try {
218
+                $token = $this->session->getId();
219
+            } catch (SessionNotAvailableException $ex) {
220
+                return;
221
+            }
222
+        } else {
223
+            $token = $appPassword;
224
+        }
225
+
226
+        if (!$this->validateToken($token)) {
227
+            // Session was invalidated
228
+            $this->logout();
229
+        }
230
+    }
231
+
232
+    /**
233
+     * Checks whether the user is logged in
234
+     *
235
+     * @return bool if logged in
236
+     */
237
+    public function isLoggedIn() {
238
+        $user = $this->getUser();
239
+        if (is_null($user)) {
240
+            return false;
241
+        }
242
+
243
+        return $user->isEnabled();
244
+    }
245
+
246
+    /**
247
+     * set the login name
248
+     *
249
+     * @param string|null $loginName for the logged in user
250
+     */
251
+    public function setLoginName($loginName) {
252
+        if (is_null($loginName)) {
253
+            $this->session->remove('loginname');
254
+        } else {
255
+            $this->session->set('loginname', $loginName);
256
+        }
257
+    }
258
+
259
+    /**
260
+     * get the login name of the current user
261
+     *
262
+     * @return string
263
+     */
264
+    public function getLoginName() {
265
+        if ($this->activeUser) {
266
+            return $this->session->get('loginname');
267
+        } else {
268
+            $uid = $this->session->get('user_id');
269
+            if ($uid) {
270
+                $this->activeUser = $this->manager->get($uid);
271
+                return $this->session->get('loginname');
272
+            } else {
273
+                return null;
274
+            }
275
+        }
276
+    }
277
+
278
+    /**
279
+     * try to log in with the provided credentials
280
+     *
281
+     * @param string $uid
282
+     * @param string $password
283
+     * @return boolean|null
284
+     * @throws LoginException
285
+     */
286
+    public function login($uid, $password) {
287
+        $this->session->regenerateId();
288
+        if ($this->validateToken($password, $uid)) {
289
+            return $this->loginWithToken($password);
290
+        } else {
291
+            return $this->loginWithPassword($uid, $password);
292
+        }
293
+        return false;
294
+    }
295
+
296
+    /**
297
+     * Tries to log in a client
298
+     *
299
+     * Checks token auth enforced
300
+     * Checks 2FA enabled
301
+     *
302
+     * @param string $user
303
+     * @param string $password
304
+     * @param IRequest $request
305
+     * @param OC\Security\Bruteforce\Throttler $throttler
306
+     * @throws LoginException
307
+     * @throws PasswordLoginForbiddenException
308
+     * @return boolean
309
+     */
310
+    public function logClientIn($user,
311
+                                $password,
312
+                                IRequest $request,
313
+                                OC\Security\Bruteforce\Throttler $throttler) {
314
+        $currentDelay = $throttler->getDelay($request->getRemoteAddress());
315
+        $throttler->sleepDelay($request->getRemoteAddress());
316
+
317
+        $isTokenPassword = $this->isTokenPassword($password);
318
+        if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
319
+            throw new PasswordLoginForbiddenException();
320
+        }
321
+        if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
322
+            throw new PasswordLoginForbiddenException();
323
+        }
324
+        if (!$this->login($user, $password) ) {
325
+            $users = $this->manager->getByEmail($user);
326
+            if (count($users) === 1) {
327
+                return $this->login($users[0]->getUID(), $password);
328
+            }
329
+
330
+            $throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
331
+            if($currentDelay === 0) {
332
+                $throttler->sleepDelay($request->getRemoteAddress());
333
+            }
334
+            return false;
335
+        }
336
+
337
+        if ($isTokenPassword) {
338
+            $this->session->set('app_password', $password);
339
+        } else if($this->supportsCookies($request)) {
340
+            // Password login, but cookies supported -> create (browser) session token
341
+            $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
342
+        }
343
+
344
+        return true;
345
+    }
346
+
347
+    protected function supportsCookies(IRequest $request) {
348
+        if (!is_null($request->getCookie('cookie_test'))) {
349
+            return true;
350
+        }
351
+        setcookie('cookie_test', 'test', $this->timeFacory->getTime() + 3600);
352
+        return false;
353
+    }
354
+
355
+    private function isTokenAuthEnforced() {
356
+        return $this->config->getSystemValue('token_auth_enforced', false);
357
+    }
358
+
359
+    protected function isTwoFactorEnforced($username) {
360
+        Util::emitHook(
361
+            '\OCA\Files_Sharing\API\Server2Server',
362
+            'preLoginNameUsedAsUserName',
363
+            array('uid' => &$username)
364
+        );
365
+        $user = $this->manager->get($username);
366
+        if (is_null($user)) {
367
+            $users = $this->manager->getByEmail($username);
368
+            if (count($users) !== 1) {
369
+                return true;
370
+            }
371
+            $user = $users[0];
372
+        }
373
+        // DI not possible due to cyclic dependencies :'-/
374
+        return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
375
+    }
376
+
377
+    /**
378
+     * Check if the given 'password' is actually a device token
379
+     *
380
+     * @param string $password
381
+     * @return boolean
382
+     */
383
+    public function isTokenPassword($password) {
384
+        try {
385
+            $this->tokenProvider->getToken($password);
386
+            return true;
387
+        } catch (InvalidTokenException $ex) {
388
+            return false;
389
+        }
390
+    }
391
+
392
+    protected function prepareUserLogin() {
393
+        // TODO: mock/inject/use non-static
394
+        // Refresh the token
395
+        \OC::$server->getCsrfTokenManager()->refreshToken();
396
+        //we need to pass the user name, which may differ from login name
397
+        $user = $this->getUser()->getUID();
398
+        OC_Util::setupFS($user);
399
+        //trigger creation of user home and /files folder
400
+        \OC::$server->getUserFolder($user);
401
+    }
402
+
403
+    /**
404
+     * Tries to login the user with HTTP Basic Authentication
405
+     *
406
+     * @todo do not allow basic auth if the user is 2FA enforced
407
+     * @param IRequest $request
408
+     * @return boolean if the login was successful
409
+     */
410
+    public function tryBasicAuthLogin(IRequest $request,
411
+                                        OC\Security\Bruteforce\Throttler $throttler) {
412
+        if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
413
+            try {
414
+                if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
415
+                    /**
416
+                     * Add DAV authenticated. This should in an ideal world not be
417
+                     * necessary but the iOS App reads cookies from anywhere instead
418
+                     * only the DAV endpoint.
419
+                     * This makes sure that the cookies will be valid for the whole scope
420
+                     * @see https://github.com/owncloud/core/issues/22893
421
+                     */
422
+                    $this->session->set(
423
+                        Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
424
+                    );
425
+                    return true;
426
+                }
427
+            } catch (PasswordLoginForbiddenException $ex) {
428
+                // Nothing to do
429
+            }
430
+        }
431
+        return false;
432
+    }
433
+
434
+    /**
435
+     * Log an user in via login name and password
436
+     *
437
+     * @param string $uid
438
+     * @param string $password
439
+     * @return boolean
440
+     * @throws LoginException if an app canceld the login process or the user is not enabled
441
+     */
442
+    private function loginWithPassword($uid, $password) {
443
+        $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
444
+        $user = $this->manager->checkPassword($uid, $password);
445
+        if ($user === false) {
446
+            // Password check failed
447
+            return false;
448
+        }
449
+
450
+        if ($user->isEnabled()) {
451
+            $this->setUser($user);
452
+            $this->setLoginName($uid);
453
+            $this->manager->emit('\OC\User', 'postLogin', array($user, $password));
454
+            if ($this->isLoggedIn()) {
455
+                $this->prepareUserLogin();
456
+                return true;
457
+            } else {
458
+                // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
459
+                $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
460
+                throw new LoginException($message);
461
+            }
462
+        } else {
463
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
464
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
465
+            throw new LoginException($message);
466
+        }
467
+        return false;
468
+    }
469
+
470
+    /**
471
+     * Log an user in with a given token (id)
472
+     *
473
+     * @param string $token
474
+     * @return boolean
475
+     * @throws LoginException if an app canceld the login process or the user is not enabled
476
+     */
477
+    private function loginWithToken($token) {
478
+        try {
479
+            $dbToken = $this->tokenProvider->getToken($token);
480
+        } catch (InvalidTokenException $ex) {
481
+            return false;
482
+        }
483
+        $uid = $dbToken->getUID();
484
+
485
+        // When logging in with token, the password must be decrypted first before passing to login hook
486
+        $password = '';
487
+        try {
488
+            $password = $this->tokenProvider->getPassword($dbToken, $token);
489
+        } catch (PasswordlessTokenException $ex) {
490
+            // Ignore and use empty string instead
491
+        }
492
+
493
+        $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
494
+
495
+        $user = $this->manager->get($uid);
496
+        if (is_null($user)) {
497
+            // user does not exist
498
+            return false;
499
+        }
500
+        if (!$user->isEnabled()) {
501
+            // disabled users can not log in
502
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
503
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
504
+            throw new LoginException($message);
505
+        }
506
+
507
+        //login
508
+        $this->setUser($user);
509
+        $this->setLoginName($dbToken->getLoginName());
510
+        $this->manager->emit('\OC\User', 'postLogin', array($user, $password));
511
+
512
+        if ($this->isLoggedIn()) {
513
+            $this->prepareUserLogin();
514
+        } else {
515
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
516
+            $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
517
+            throw new LoginException($message);
518
+        }
519
+
520
+        return true;
521
+    }
522
+
523
+    /**
524
+     * Create a new session token for the given user credentials
525
+     *
526
+     * @param IRequest $request
527
+     * @param string $uid user UID
528
+     * @param string $loginName login name
529
+     * @param string $password
530
+     * @return boolean
531
+     */
532
+    public function createSessionToken(IRequest $request, $uid, $loginName, $password = null) {
533
+        if (is_null($this->manager->get($uid))) {
534
+            // User does not exist
535
+            return false;
536
+        }
537
+        $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
538
+        try {
539
+            $sessionId = $this->session->getId();
540
+            $pwd = $this->getPassword($password);
541
+            $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name);
542
+            return true;
543
+        } catch (SessionNotAvailableException $ex) {
544
+            // This can happen with OCC, where a memory session is used
545
+            // if a memory session is used, we shouldn't create a session token anyway
546
+            return false;
547
+        }
548
+    }
549
+
550
+    /**
551
+     * Checks if the given password is a token.
552
+     * If yes, the password is extracted from the token.
553
+     * If no, the same password is returned.
554
+     *
555
+     * @param string $password either the login password or a device token
556
+     * @return string|null the password or null if none was set in the token
557
+     */
558
+    private function getPassword($password) {
559
+        if (is_null($password)) {
560
+            // This is surely no token ;-)
561
+            return null;
562
+        }
563
+        try {
564
+            $token = $this->tokenProvider->getToken($password);
565
+            try {
566
+                return $this->tokenProvider->getPassword($token, $password);
567
+            } catch (PasswordlessTokenException $ex) {
568
+                return null;
569
+            }
570
+        } catch (InvalidTokenException $ex) {
571
+            return $password;
572
+        }
573
+    }
574
+
575
+    /**
576
+     * @param IToken $dbToken
577
+     * @param string $token
578
+     * @return boolean
579
+     */
580
+    private function checkTokenCredentials(IToken $dbToken, $token) {
581
+        // Check whether login credentials are still valid and the user was not disabled
582
+        // This check is performed each 5 minutes
583
+        $lastCheck = $dbToken->getLastCheck() ? : 0;
584
+        $now = $this->timeFacory->getTime();
585
+        if ($lastCheck > ($now - 60 * 5)) {
586
+            // Checked performed recently, nothing to do now
587
+            return true;
588
+        }
589
+
590
+        try {
591
+            $pwd = $this->tokenProvider->getPassword($dbToken, $token);
592
+        } catch (InvalidTokenException $ex) {
593
+            // An invalid token password was used -> log user out
594
+            return false;
595
+        } catch (PasswordlessTokenException $ex) {
596
+            // Token has no password
597
+
598
+            if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
599
+                $this->tokenProvider->invalidateToken($token);
600
+                return false;
601
+            }
602
+
603
+            $dbToken->setLastCheck($now);
604
+            $this->tokenProvider->updateToken($dbToken);
605
+            return true;
606
+        }
607
+
608
+        if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false
609
+            || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) {
610
+            $this->tokenProvider->invalidateToken($token);
611
+            // Password has changed or user was disabled -> log user out
612
+            return false;
613
+        }
614
+        $dbToken->setLastCheck($now);
615
+        $this->tokenProvider->updateToken($dbToken);
616
+        return true;
617
+    }
618
+
619
+    /**
620
+     * Check if the given token exists and performs password/user-enabled checks
621
+     *
622
+     * Invalidates the token if checks fail
623
+     *
624
+     * @param string $token
625
+     * @param string $user login name
626
+     * @return boolean
627
+     */
628
+    private function validateToken($token, $user = null) {
629
+        try {
630
+            $dbToken = $this->tokenProvider->getToken($token);
631
+        } catch (InvalidTokenException $ex) {
632
+            return false;
633
+        }
634
+
635
+        // Check if login names match
636
+        if (!is_null($user) && $dbToken->getLoginName() !== $user) {
637
+            // TODO: this makes it imposssible to use different login names on browser and client
638
+            // e.g. login by e-mail '[email protected]' on browser for generating the token will not
639
+            //      allow to use the client token with the login name 'user'.
640
+            return false;
641
+        }
642
+
643
+        if (!$this->checkTokenCredentials($dbToken, $token)) {
644
+            return false;
645
+        }
646
+
647
+        $this->tokenProvider->updateTokenActivity($dbToken);
648
+
649
+        return true;
650
+    }
651
+
652
+    /**
653
+     * Tries to login the user with auth token header
654
+     *
655
+     * @todo check remember me cookie
656
+     * @return boolean
657
+     */
658
+    public function tryTokenLogin(IRequest $request) {
659
+        $authHeader = $request->getHeader('Authorization');
660
+        if (strpos($authHeader, 'token ') === false) {
661
+            // No auth header, let's try session id
662
+            try {
663
+                $token = $this->session->getId();
664
+            } catch (SessionNotAvailableException $ex) {
665
+                return false;
666
+            }
667
+        } else {
668
+            $token = substr($authHeader, 6);
669
+        }
670
+
671
+        if (!$this->loginWithToken($token)) {
672
+            return false;
673
+        }
674
+        if(!$this->validateToken($token)) {
675
+            return false;
676
+        }
677
+        return true;
678
+    }
679
+
680
+    /**
681
+     * perform login using the magic cookie (remember login)
682
+     *
683
+     * @param string $uid the username
684
+     * @param string $currentToken
685
+     * @return bool
686
+     */
687
+    public function loginWithCookie($uid, $currentToken) {
688
+        $this->session->regenerateId();
689
+        $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
690
+        $user = $this->manager->get($uid);
691
+        if (is_null($user)) {
692
+            // user does not exist
693
+            return false;
694
+        }
695
+
696
+        // get stored tokens
697
+        $tokens = OC::$server->getConfig()->getUserKeys($uid, 'login_token');
698
+        // test cookies token against stored tokens
699
+        if (!in_array($currentToken, $tokens, true)) {
700
+            return false;
701
+        }
702
+        // replace successfully used token with a new one
703
+        OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken);
704
+        $newToken = OC::$server->getSecureRandom()->generate(32);
705
+        OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time());
706
+        $this->setMagicInCookie($user->getUID(), $newToken);
707
+
708
+        //login
709
+        $this->setUser($user);
710
+        $this->manager->emit('\OC\User', 'postRememberedLogin', array($user));
711
+        return true;
712
+    }
713
+
714
+    /**
715
+     * logout the user from the session
716
+     */
717
+    public function logout() {
718
+        $this->manager->emit('\OC\User', 'logout');
719
+        $user = $this->getUser();
720
+        if (!is_null($user)) {
721
+            try {
722
+                $this->tokenProvider->invalidateToken($this->session->getId());
723
+            } catch (SessionNotAvailableException $ex) {
724 724
 				
725
-			}
726
-		}
727
-		$this->setUser(null);
728
-		$this->setLoginName(null);
729
-		$this->unsetMagicInCookie();
730
-		$this->session->clear();
731
-	}
732
-
733
-	/**
734
-	 * Set cookie value to use in next page load
735
-	 *
736
-	 * @param string $username username to be set
737
-	 * @param string $token
738
-	 */
739
-	public function setMagicInCookie($username, $token) {
740
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
741
-		$expires = time() + OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
742
-		setcookie('oc_username', $username, $expires, OC::$WEBROOT, '', $secureCookie, true);
743
-		setcookie('oc_token', $token, $expires, OC::$WEBROOT, '', $secureCookie, true);
744
-		setcookie('oc_remember_login', '1', $expires, OC::$WEBROOT, '', $secureCookie, true);
745
-	}
746
-
747
-	/**
748
-	 * Remove cookie for "remember username"
749
-	 */
750
-	public function unsetMagicInCookie() {
751
-		//TODO: DI for cookies and IRequest
752
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
753
-
754
-		unset($_COOKIE['oc_username']); //TODO: DI
755
-		unset($_COOKIE['oc_token']);
756
-		unset($_COOKIE['oc_remember_login']);
757
-		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
758
-		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
759
-		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
760
-		// old cookies might be stored under /webroot/ instead of /webroot
761
-		// and Firefox doesn't like it!
762
-		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
763
-		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
764
-		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
765
-	}
766
-
767
-	/**
768
-	 * Update password of the browser session token if there is one
769
-	 *
770
-	 * @param string $password
771
-	 */
772
-	public function updateSessionTokenPassword($password) {
773
-		try {
774
-			$sessionId = $this->session->getId();
775
-			$token = $this->tokenProvider->getToken($sessionId);
776
-			$this->tokenProvider->setPassword($token, $sessionId, $password);
777
-		} catch (SessionNotAvailableException $ex) {
778
-			// Nothing to do
779
-		} catch (InvalidTokenException $ex) {
780
-			// Nothing to do
781
-		}
782
-	}
725
+            }
726
+        }
727
+        $this->setUser(null);
728
+        $this->setLoginName(null);
729
+        $this->unsetMagicInCookie();
730
+        $this->session->clear();
731
+    }
732
+
733
+    /**
734
+     * Set cookie value to use in next page load
735
+     *
736
+     * @param string $username username to be set
737
+     * @param string $token
738
+     */
739
+    public function setMagicInCookie($username, $token) {
740
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
741
+        $expires = time() + OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
742
+        setcookie('oc_username', $username, $expires, OC::$WEBROOT, '', $secureCookie, true);
743
+        setcookie('oc_token', $token, $expires, OC::$WEBROOT, '', $secureCookie, true);
744
+        setcookie('oc_remember_login', '1', $expires, OC::$WEBROOT, '', $secureCookie, true);
745
+    }
746
+
747
+    /**
748
+     * Remove cookie for "remember username"
749
+     */
750
+    public function unsetMagicInCookie() {
751
+        //TODO: DI for cookies and IRequest
752
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
753
+
754
+        unset($_COOKIE['oc_username']); //TODO: DI
755
+        unset($_COOKIE['oc_token']);
756
+        unset($_COOKIE['oc_remember_login']);
757
+        setcookie('oc_username', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
758
+        setcookie('oc_token', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
759
+        setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
760
+        // old cookies might be stored under /webroot/ instead of /webroot
761
+        // and Firefox doesn't like it!
762
+        setcookie('oc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
763
+        setcookie('oc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
764
+        setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
765
+    }
766
+
767
+    /**
768
+     * Update password of the browser session token if there is one
769
+     *
770
+     * @param string $password
771
+     */
772
+    public function updateSessionTokenPassword($password) {
773
+        try {
774
+            $sessionId = $this->session->getId();
775
+            $token = $this->tokenProvider->getToken($sessionId);
776
+            $this->tokenProvider->setPassword($token, $sessionId, $password);
777
+        } catch (SessionNotAvailableException $ex) {
778
+            // Nothing to do
779
+        } catch (InvalidTokenException $ex) {
780
+            // Nothing to do
781
+        }
782
+    }
783 783
 
784 784
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -321,14 +321,14 @@  discard block
 block discarded – undo
321 321
 		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
322 322
 			throw new PasswordLoginForbiddenException();
323 323
 		}
324
-		if (!$this->login($user, $password) ) {
324
+		if (!$this->login($user, $password)) {
325 325
 			$users = $this->manager->getByEmail($user);
326 326
 			if (count($users) === 1) {
327 327
 				return $this->login($users[0]->getUID(), $password);
328 328
 			}
329 329
 
330 330
 			$throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
331
-			if($currentDelay === 0) {
331
+			if ($currentDelay === 0) {
332 332
 				$throttler->sleepDelay($request->getRemoteAddress());
333 333
 			}
334 334
 			return false;
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
 
337 337
 		if ($isTokenPassword) {
338 338
 			$this->session->set('app_password', $password);
339
-		} else if($this->supportsCookies($request)) {
339
+		} else if ($this->supportsCookies($request)) {
340 340
 			// Password login, but cookies supported -> create (browser) session token
341 341
 			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
342 342
 		}
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
 	private function checkTokenCredentials(IToken $dbToken, $token) {
581 581
 		// Check whether login credentials are still valid and the user was not disabled
582 582
 		// This check is performed each 5 minutes
583
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
583
+		$lastCheck = $dbToken->getLastCheck() ?: 0;
584 584
 		$now = $this->timeFacory->getTime();
585 585
 		if ($lastCheck > ($now - 60 * 5)) {
586 586
 			// Checked performed recently, nothing to do now
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
 		if (!$this->loginWithToken($token)) {
672 672
 			return false;
673 673
 		}
674
-		if(!$this->validateToken($token)) {
674
+		if (!$this->validateToken($token)) {
675 675
 			return false;
676 676
 		}
677 677
 		return true;
@@ -759,9 +759,9 @@  discard block
 block discarded – undo
759 759
 		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
760 760
 		// old cookies might be stored under /webroot/ instead of /webroot
761 761
 		// and Firefox doesn't like it!
762
-		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
763
-		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
764
-		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
762
+		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
763
+		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
764
+		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
765 765
 	}
766 766
 
767 767
 	/**
Please login to merge, or discard this patch.
lib/private/legacy/app.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -1333,6 +1333,9 @@
 block discarded – undo
1333 1333
 		}
1334 1334
 	}
1335 1335
 
1336
+	/**
1337
+	 * @param string $lang
1338
+	 */
1336 1339
 	protected static function findBestL10NOption($options, $lang) {
1337 1340
 		$fallback = $similarLangFallback = $englishFallback = false;
1338 1341
 
Please login to merge, or discard this patch.
Indentation   +1366 added lines, -1366 removed lines patch added patch discarded remove patch
@@ -59,1370 +59,1370 @@
 block discarded – undo
59 59
  * upgrading and removing apps.
60 60
  */
61 61
 class OC_App {
62
-	static private $appVersion = [];
63
-	static private $adminForms = array();
64
-	static private $personalForms = array();
65
-	static private $appInfo = array();
66
-	static private $appTypes = array();
67
-	static private $loadedApps = array();
68
-	static private $altLogin = array();
69
-	static private $alreadyRegistered = [];
70
-	const officialApp = 200;
71
-
72
-	/**
73
-	 * clean the appId
74
-	 *
75
-	 * @param string|boolean $app AppId that needs to be cleaned
76
-	 * @return string
77
-	 */
78
-	public static function cleanAppId($app) {
79
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
80
-	}
81
-
82
-	/**
83
-	 * Check if an app is loaded
84
-	 *
85
-	 * @param string $app
86
-	 * @return bool
87
-	 */
88
-	public static function isAppLoaded($app) {
89
-		return in_array($app, self::$loadedApps, true);
90
-	}
91
-
92
-	/**
93
-	 * loads all apps
94
-	 *
95
-	 * @param string[] | string | null $types
96
-	 * @return bool
97
-	 *
98
-	 * This function walks through the ownCloud directory and loads all apps
99
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
100
-	 * exists.
101
-	 *
102
-	 * if $types is set, only apps of those types will be loaded
103
-	 */
104
-	public static function loadApps($types = null) {
105
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
106
-			return false;
107
-		}
108
-		// Load the enabled apps here
109
-		$apps = self::getEnabledApps();
110
-
111
-		// Add each apps' folder as allowed class path
112
-		foreach($apps as $app) {
113
-			$path = self::getAppPath($app);
114
-			if($path !== false) {
115
-				self::registerAutoloading($app, $path);
116
-			}
117
-		}
118
-
119
-		// prevent app.php from printing output
120
-		ob_start();
121
-		foreach ($apps as $app) {
122
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
123
-				self::loadApp($app);
124
-			}
125
-		}
126
-		ob_end_clean();
127
-
128
-		return true;
129
-	}
130
-
131
-	/**
132
-	 * load a single app
133
-	 *
134
-	 * @param string $app
135
-	 * @param bool $checkUpgrade whether an upgrade check should be done
136
-	 * @throws \OC\NeedsUpdateException
137
-	 */
138
-	public static function loadApp($app, $checkUpgrade = true) {
139
-		self::$loadedApps[] = $app;
140
-		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
142
-			return;
143
-		}
144
-
145
-		// in case someone calls loadApp() directly
146
-		self::registerAutoloading($app, $appPath);
147
-
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
-			if ($checkUpgrade and self::shouldUpgrade($app)) {
151
-				throw new \OC\NeedsUpdateException();
152
-			}
153
-			self::requireAppFile($app);
154
-			if (self::isType($app, array('authentication'))) {
155
-				// since authentication apps affect the "is app enabled for group" check,
156
-				// the enabled apps cache needs to be cleared to make sure that the
157
-				// next time getEnableApps() is called it will also include apps that were
158
-				// enabled for groups
159
-				self::$enabledAppsCache = array();
160
-			}
161
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * @internal
167
-	 * @param string $app
168
-	 * @param string $path
169
-	 */
170
-	public static function registerAutoloading($app, $path) {
171
-		$key = $app . '-' . $path;
172
-		if(isset(self::$alreadyRegistered[$key])) {
173
-			return;
174
-		}
175
-		self::$alreadyRegistered[$key] = true;
176
-		// Register on PSR-4 composer autoloader
177
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
178
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
179
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
180
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
181
-		}
182
-
183
-		// Register on legacy autoloader
184
-		\OC::$loader->addValidRoot($path);
185
-	}
186
-
187
-	/**
188
-	 * Load app.php from the given app
189
-	 *
190
-	 * @param string $app app name
191
-	 */
192
-	private static function requireAppFile($app) {
193
-		try {
194
-			// encapsulated here to avoid variable scope conflicts
195
-			require_once $app . '/appinfo/app.php';
196
-		} catch (Error $ex) {
197
-			\OC::$server->getLogger()->logException($ex);
198
-			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
199
-			if (!in_array($app, $blacklist)) {
200
-				self::disable($app);
201
-			}
202
-		}
203
-	}
204
-
205
-	/**
206
-	 * check if an app is of a specific type
207
-	 *
208
-	 * @param string $app
209
-	 * @param string|array $types
210
-	 * @return bool
211
-	 */
212
-	public static function isType($app, $types) {
213
-		if (is_string($types)) {
214
-			$types = array($types);
215
-		}
216
-		$appTypes = self::getAppTypes($app);
217
-		foreach ($types as $type) {
218
-			if (array_search($type, $appTypes) !== false) {
219
-				return true;
220
-			}
221
-		}
222
-		return false;
223
-	}
224
-
225
-	/**
226
-	 * get the types of an app
227
-	 *
228
-	 * @param string $app
229
-	 * @return array
230
-	 */
231
-	private static function getAppTypes($app) {
232
-		//load the cache
233
-		if (count(self::$appTypes) == 0) {
234
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
235
-		}
236
-
237
-		if (isset(self::$appTypes[$app])) {
238
-			return explode(',', self::$appTypes[$app]);
239
-		} else {
240
-			return array();
241
-		}
242
-	}
243
-
244
-	/**
245
-	 * read app types from info.xml and cache them in the database
246
-	 */
247
-	public static function setAppTypes($app) {
248
-		$appData = self::getAppInfo($app);
249
-		if(!is_array($appData)) {
250
-			return;
251
-		}
252
-
253
-		if (isset($appData['types'])) {
254
-			$appTypes = implode(',', $appData['types']);
255
-		} else {
256
-			$appTypes = '';
257
-		}
258
-
259
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
260
-	}
261
-
262
-	/**
263
-	 * check if app is shipped
264
-	 *
265
-	 * @param string $appId the id of the app to check
266
-	 * @return bool
267
-	 *
268
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
269
-	 */
270
-	public static function isShipped($appId) {
271
-		return \OC::$server->getAppManager()->isShipped($appId);
272
-	}
273
-
274
-	/**
275
-	 * get all enabled apps
276
-	 */
277
-	protected static $enabledAppsCache = array();
278
-
279
-	/**
280
-	 * Returns apps enabled for the current user.
281
-	 *
282
-	 * @param bool $forceRefresh whether to refresh the cache
283
-	 * @param bool $all whether to return apps for all users, not only the
284
-	 * currently logged in one
285
-	 * @return string[]
286
-	 */
287
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
288
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
289
-			return array();
290
-		}
291
-		// in incognito mode or when logged out, $user will be false,
292
-		// which is also the case during an upgrade
293
-		$appManager = \OC::$server->getAppManager();
294
-		if ($all) {
295
-			$user = null;
296
-		} else {
297
-			$user = \OC::$server->getUserSession()->getUser();
298
-		}
299
-
300
-		if (is_null($user)) {
301
-			$apps = $appManager->getInstalledApps();
302
-		} else {
303
-			$apps = $appManager->getEnabledAppsForUser($user);
304
-		}
305
-		$apps = array_filter($apps, function ($app) {
306
-			return $app !== 'files';//we add this manually
307
-		});
308
-		sort($apps);
309
-		array_unshift($apps, 'files');
310
-		return $apps;
311
-	}
312
-
313
-	/**
314
-	 * checks whether or not an app is enabled
315
-	 *
316
-	 * @param string $app app
317
-	 * @return bool
318
-	 *
319
-	 * This function checks whether or not an app is enabled.
320
-	 */
321
-	public static function isEnabled($app) {
322
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
323
-	}
324
-
325
-	/**
326
-	 * enables an app
327
-	 *
328
-	 * @param mixed $app app
329
-	 * @param array $groups (optional) when set, only these groups will have access to the app
330
-	 * @throws \Exception
331
-	 * @return void
332
-	 *
333
-	 * This function set an app as enabled in appconfig.
334
-	 */
335
-	public static function enable($app, $groups = null) {
336
-		self::$enabledAppsCache = array(); // flush
337
-		if (!Installer::isInstalled($app)) {
338
-			$app = self::installApp($app);
339
-		}
340
-
341
-		$appManager = \OC::$server->getAppManager();
342
-		if (!is_null($groups)) {
343
-			$groupManager = \OC::$server->getGroupManager();
344
-			$groupsList = [];
345
-			foreach ($groups as $group) {
346
-				$groupItem = $groupManager->get($group);
347
-				if ($groupItem instanceof \OCP\IGroup) {
348
-					$groupsList[] = $groupManager->get($group);
349
-				}
350
-			}
351
-			$appManager->enableAppForGroups($app, $groupsList);
352
-		} else {
353
-			$appManager->enableApp($app);
354
-		}
355
-
356
-		$info = self::getAppInfo($app);
357
-		if(isset($info['settings']) && is_array($info['settings'])) {
358
-			$appPath = self::getAppPath($app);
359
-			self::registerAutoloading($app, $appPath);
360
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
361
-		}
362
-	}
363
-
364
-	/**
365
-	 * @param string $app
366
-	 * @return int
367
-	 */
368
-	private static function downloadApp($app) {
369
-		$ocsClient = new OCSClient(
370
-			\OC::$server->getHTTPClientService(),
371
-			\OC::$server->getConfig(),
372
-			\OC::$server->getLogger()
373
-		);
374
-		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
375
-		$download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
376
-		if(isset($download['downloadlink']) and $download['downloadlink']!='') {
377
-			// Replace spaces in download link without encoding entire URL
378
-			$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
379
-			$info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
380
-			$app = Installer::installApp($info);
381
-		}
382
-		return $app;
383
-	}
384
-
385
-	/**
386
-	 * @param string $app
387
-	 * @return bool
388
-	 */
389
-	public static function removeApp($app) {
390
-		if (self::isShipped($app)) {
391
-			return false;
392
-		}
393
-
394
-		return Installer::removeApp($app);
395
-	}
396
-
397
-	/**
398
-	 * This function set an app as disabled in appconfig.
399
-	 *
400
-	 * @param string $app app
401
-	 * @throws Exception
402
-	 */
403
-	public static function disable($app) {
404
-		// Convert OCS ID to regular application identifier
405
-		if(self::getInternalAppIdByOcs($app) !== false) {
406
-			$app = self::getInternalAppIdByOcs($app);
407
-		}
408
-
409
-		// flush
410
-		self::$enabledAppsCache = array();
411
-
412
-		// run uninstall steps
413
-		$appData = OC_App::getAppInfo($app);
414
-		if (!is_null($appData)) {
415
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
416
-		}
417
-
418
-		// emit disable hook - needed anymore ?
419
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
420
-
421
-		// finally disable it
422
-		$appManager = \OC::$server->getAppManager();
423
-		$appManager->disableApp($app);
424
-	}
425
-
426
-	/**
427
-	 * Returns the Settings Navigation
428
-	 *
429
-	 * @return string[]
430
-	 *
431
-	 * This function returns an array containing all settings pages added. The
432
-	 * entries are sorted by the key 'order' ascending.
433
-	 */
434
-	public static function getSettingsNavigation() {
435
-		$l = \OC::$server->getL10N('lib');
436
-		$urlGenerator = \OC::$server->getURLGenerator();
437
-
438
-		$settings = array();
439
-		// by default, settings only contain the help menu
440
-		if (OC_Util::getEditionString() === '' &&
441
-			\OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
442
-		) {
443
-			$settings = array(
444
-				array(
445
-					"id" => "help",
446
-					"order" => 1000,
447
-					"href" => $urlGenerator->linkToRoute('settings_help'),
448
-					"name" => $l->t("Help"),
449
-					"icon" => $urlGenerator->imagePath("settings", "help.svg")
450
-				)
451
-			);
452
-		}
453
-
454
-		// if the user is logged-in
455
-		if (OC_User::isLoggedIn()) {
456
-			// personal menu
457
-			$settings[] = array(
458
-				"id" => "personal",
459
-				"order" => 1,
460
-				"href" => $urlGenerator->linkToRoute('settings_personal'),
461
-				"name" => $l->t("Personal"),
462
-				"icon" => $urlGenerator->imagePath("settings", "personal.svg")
463
-			);
464
-
465
-			//SubAdmins are also allowed to access user management
466
-			$userObject = \OC::$server->getUserSession()->getUser();
467
-			$isSubAdmin = false;
468
-			if($userObject !== null) {
469
-				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
470
-			}
471
-			if ($isSubAdmin) {
472
-				// admin users menu
473
-				$settings[] = array(
474
-					"id" => "core_users",
475
-					"order" => 2,
476
-					"href" => $urlGenerator->linkToRoute('settings_users'),
477
-					"name" => $l->t("Users"),
478
-					"icon" => $urlGenerator->imagePath("settings", "users.svg")
479
-				);
480
-			}
481
-
482
-			// if the user is an admin
483
-			if (OC_User::isAdminUser(OC_User::getUser())) {
484
-				// admin settings
485
-				$settings[] = array(
486
-					"id" => "admin",
487
-					"order" => 1000,
488
-					"href" => $urlGenerator->linkToRoute('settings.AdminSettings.index'),
489
-					"name" => $l->t("Admin"),
490
-					"icon" => $urlGenerator->imagePath("settings", "admin.svg")
491
-				);
492
-			}
493
-		}
494
-
495
-		$navigation = self::proceedNavigation($settings);
496
-		return $navigation;
497
-	}
498
-
499
-	// This is private as well. It simply works, so don't ask for more details
500
-	private static function proceedNavigation($list) {
501
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
502
-		foreach ($list as &$navEntry) {
503
-			if ($navEntry['id'] == $activeApp) {
504
-				$navEntry['active'] = true;
505
-			} else {
506
-				$navEntry['active'] = false;
507
-			}
508
-		}
509
-		unset($navEntry);
510
-
511
-		usort($list, function($a, $b) {
512
-			if (isset($a['order']) && isset($b['order'])) {
513
-				return ($a['order'] < $b['order']) ? -1 : 1;
514
-			} else if (isset($a['order']) || isset($b['order'])) {
515
-				return isset($a['order']) ? -1 : 1;
516
-			} else {
517
-				return ($a['name'] < $b['name']) ? -1 : 1;
518
-			}
519
-		});
520
-
521
-		return $list;
522
-	}
523
-
524
-	/**
525
-	 * Get the path where to install apps
526
-	 *
527
-	 * @return string|false
528
-	 */
529
-	public static function getInstallPath() {
530
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
531
-			return false;
532
-		}
533
-
534
-		foreach (OC::$APPSROOTS as $dir) {
535
-			if (isset($dir['writable']) && $dir['writable'] === true) {
536
-				return $dir['path'];
537
-			}
538
-		}
539
-
540
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
541
-		return null;
542
-	}
543
-
544
-
545
-	/**
546
-	 * search for an app in all app-directories
547
-	 *
548
-	 * @param string $appId
549
-	 * @return false|string
550
-	 */
551
-	protected static function findAppInDirectories($appId) {
552
-		$sanitizedAppId = self::cleanAppId($appId);
553
-		if($sanitizedAppId !== $appId) {
554
-			return false;
555
-		}
556
-		static $app_dir = array();
557
-
558
-		if (isset($app_dir[$appId])) {
559
-			return $app_dir[$appId];
560
-		}
561
-
562
-		$possibleApps = array();
563
-		foreach (OC::$APPSROOTS as $dir) {
564
-			if (file_exists($dir['path'] . '/' . $appId)) {
565
-				$possibleApps[] = $dir;
566
-			}
567
-		}
568
-
569
-		if (empty($possibleApps)) {
570
-			return false;
571
-		} elseif (count($possibleApps) === 1) {
572
-			$dir = array_shift($possibleApps);
573
-			$app_dir[$appId] = $dir;
574
-			return $dir;
575
-		} else {
576
-			$versionToLoad = array();
577
-			foreach ($possibleApps as $possibleApp) {
578
-				$version = self::getAppVersionByPath($possibleApp['path']);
579
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
580
-					$versionToLoad = array(
581
-						'dir' => $possibleApp,
582
-						'version' => $version,
583
-					);
584
-				}
585
-			}
586
-			$app_dir[$appId] = $versionToLoad['dir'];
587
-			return $versionToLoad['dir'];
588
-			//TODO - write test
589
-		}
590
-	}
591
-
592
-	/**
593
-	 * Get the directory for the given app.
594
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
595
-	 *
596
-	 * @param string $appId
597
-	 * @return string|false
598
-	 */
599
-	public static function getAppPath($appId) {
600
-		if ($appId === null || trim($appId) === '') {
601
-			return false;
602
-		}
603
-
604
-		if (($dir = self::findAppInDirectories($appId)) != false) {
605
-			return $dir['path'] . '/' . $appId;
606
-		}
607
-		return false;
608
-	}
609
-
610
-
611
-	/**
612
-	 * check if an app's directory is writable
613
-	 *
614
-	 * @param string $appId
615
-	 * @return bool
616
-	 */
617
-	public static function isAppDirWritable($appId) {
618
-		$path = self::getAppPath($appId);
619
-		return ($path !== false) ? is_writable($path) : false;
620
-	}
621
-
622
-	/**
623
-	 * Get the path for the given app on the access
624
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
625
-	 *
626
-	 * @param string $appId
627
-	 * @return string|false
628
-	 */
629
-	public static function getAppWebPath($appId) {
630
-		if (($dir = self::findAppInDirectories($appId)) != false) {
631
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
632
-		}
633
-		return false;
634
-	}
635
-
636
-	/**
637
-	 * get the last version of the app from appinfo/info.xml
638
-	 *
639
-	 * @param string $appId
640
-	 * @return string
641
-	 */
642
-	public static function getAppVersion($appId) {
643
-		if (!isset(self::$appVersion[$appId])) {
644
-			$file = self::getAppPath($appId);
645
-			self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
646
-		}
647
-		return self::$appVersion[$appId];
648
-	}
649
-
650
-	/**
651
-	 * get app's version based on it's path
652
-	 *
653
-	 * @param string $path
654
-	 * @return string
655
-	 */
656
-	public static function getAppVersionByPath($path) {
657
-		$infoFile = $path . '/appinfo/info.xml';
658
-		$appData = self::getAppInfo($infoFile, true);
659
-		return isset($appData['version']) ? $appData['version'] : '';
660
-	}
661
-
662
-
663
-	/**
664
-	 * Read all app metadata from the info.xml file
665
-	 *
666
-	 * @param string $appId id of the app or the path of the info.xml file
667
-	 * @param bool $path
668
-	 * @param string $lang
669
-	 * @return array|null
670
-	 * @note all data is read from info.xml, not just pre-defined fields
671
-	 */
672
-	public static function getAppInfo($appId, $path = false, $lang = null) {
673
-		if ($path) {
674
-			$file = $appId;
675
-		} else {
676
-			if ($lang === null && isset(self::$appInfo[$appId])) {
677
-				return self::$appInfo[$appId];
678
-			}
679
-			$appPath = self::getAppPath($appId);
680
-			if($appPath === false) {
681
-				return null;
682
-			}
683
-			$file = $appPath . '/appinfo/info.xml';
684
-		}
685
-
686
-		$parser = new \OC\App\InfoParser(\OC::$server->getURLGenerator());
687
-		$data = $parser->parse($file);
688
-
689
-		if (is_array($data)) {
690
-			$data = OC_App::parseAppInfo($data, $lang);
691
-		}
692
-		if(isset($data['ocsid'])) {
693
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
694
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
695
-				$data['ocsid'] = $storedId;
696
-			}
697
-		}
698
-
699
-		if ($lang === null) {
700
-			self::$appInfo[$appId] = $data;
701
-		}
702
-
703
-		return $data;
704
-	}
705
-
706
-	/**
707
-	 * Returns the navigation
708
-	 *
709
-	 * @return array
710
-	 *
711
-	 * This function returns an array containing all entries added. The
712
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
713
-	 * given for each app the following keys exist:
714
-	 *   - active: boolean, signals if the user is on this navigation entry
715
-	 */
716
-	public static function getNavigation() {
717
-		$entries = OC::$server->getNavigationManager()->getAll();
718
-		$navigation = self::proceedNavigation($entries);
719
-		return $navigation;
720
-	}
721
-
722
-	/**
723
-	 * get the id of loaded app
724
-	 *
725
-	 * @return string
726
-	 */
727
-	public static function getCurrentApp() {
728
-		$request = \OC::$server->getRequest();
729
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
730
-		$topFolder = substr($script, 0, strpos($script, '/'));
731
-		if (empty($topFolder)) {
732
-			$path_info = $request->getPathInfo();
733
-			if ($path_info) {
734
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
735
-			}
736
-		}
737
-		if ($topFolder == 'apps') {
738
-			$length = strlen($topFolder);
739
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
740
-		} else {
741
-			return $topFolder;
742
-		}
743
-	}
744
-
745
-	/**
746
-	 * @param string $type
747
-	 * @return array
748
-	 */
749
-	public static function getForms($type) {
750
-		$forms = array();
751
-		switch ($type) {
752
-			case 'admin':
753
-				$source = self::$adminForms;
754
-				break;
755
-			case 'personal':
756
-				$source = self::$personalForms;
757
-				break;
758
-			default:
759
-				return array();
760
-		}
761
-		foreach ($source as $form) {
762
-			$forms[] = include $form;
763
-		}
764
-		return $forms;
765
-	}
766
-
767
-	/**
768
-	 * register an admin form to be shown
769
-	 *
770
-	 * @param string $app
771
-	 * @param string $page
772
-	 */
773
-	public static function registerAdmin($app, $page) {
774
-		self::$adminForms[] = $app . '/' . $page . '.php';
775
-	}
776
-
777
-	/**
778
-	 * register a personal form to be shown
779
-	 * @param string $app
780
-	 * @param string $page
781
-	 */
782
-	public static function registerPersonal($app, $page) {
783
-		self::$personalForms[] = $app . '/' . $page . '.php';
784
-	}
785
-
786
-	/**
787
-	 * @param array $entry
788
-	 */
789
-	public static function registerLogIn(array $entry) {
790
-		self::$altLogin[] = $entry;
791
-	}
792
-
793
-	/**
794
-	 * @return array
795
-	 */
796
-	public static function getAlternativeLogIns() {
797
-		return self::$altLogin;
798
-	}
799
-
800
-	/**
801
-	 * get a list of all apps in the apps folder
802
-	 *
803
-	 * @return array an array of app names (string IDs)
804
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
805
-	 */
806
-	public static function getAllApps() {
807
-
808
-		$apps = array();
809
-
810
-		foreach (OC::$APPSROOTS as $apps_dir) {
811
-			if (!is_readable($apps_dir['path'])) {
812
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
813
-				continue;
814
-			}
815
-			$dh = opendir($apps_dir['path']);
816
-
817
-			if (is_resource($dh)) {
818
-				while (($file = readdir($dh)) !== false) {
819
-
820
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
821
-
822
-						$apps[] = $file;
823
-					}
824
-				}
825
-			}
826
-		}
827
-
828
-		return $apps;
829
-	}
830
-
831
-	/**
832
-	 * List all apps, this is used in apps.php
833
-	 *
834
-	 * @param bool $onlyLocal
835
-	 * @param bool $includeUpdateInfo Should we check whether there is an update
836
-	 *                                in the app store?
837
-	 * @param OCSClient $ocsClient
838
-	 * @return array
839
-	 */
840
-	public static function listAllApps($onlyLocal = false,
841
-									   $includeUpdateInfo = true,
842
-									   OCSClient $ocsClient) {
843
-		$installedApps = OC_App::getAllApps();
844
-
845
-		//TODO which apps do we want to blacklist and how do we integrate
846
-		// blacklisting with the multi apps folder feature?
847
-
848
-		//we don't want to show configuration for these
849
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
850
-		$appList = array();
851
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
852
-
853
-		foreach ($installedApps as $app) {
854
-			if (array_search($app, $blacklist) === false) {
855
-
856
-				$info = OC_App::getAppInfo($app, false, $langCode);
857
-				if (!is_array($info)) {
858
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
859
-					continue;
860
-				}
861
-
862
-				if (!isset($info['name'])) {
863
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
864
-					continue;
865
-				}
866
-
867
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
868
-				$info['groups'] = null;
869
-				if ($enabled === 'yes') {
870
-					$active = true;
871
-				} else if ($enabled === 'no') {
872
-					$active = false;
873
-				} else {
874
-					$active = true;
875
-					$info['groups'] = $enabled;
876
-				}
877
-
878
-				$info['active'] = $active;
879
-
880
-				if (self::isShipped($app)) {
881
-					$info['internal'] = true;
882
-					$info['level'] = self::officialApp;
883
-					$info['removable'] = false;
884
-				} else {
885
-					$info['internal'] = false;
886
-					$info['removable'] = true;
887
-				}
888
-
889
-				$info['update'] = ($includeUpdateInfo) ? Installer::isUpdateAvailable($app) : null;
890
-
891
-				$appPath = self::getAppPath($app);
892
-				if($appPath !== false) {
893
-					$appIcon = $appPath . '/img/' . $app . '.svg';
894
-					if (file_exists($appIcon)) {
895
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
896
-						$info['previewAsIcon'] = true;
897
-					} else {
898
-						$appIcon = $appPath . '/img/app.svg';
899
-						if (file_exists($appIcon)) {
900
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
901
-							$info['previewAsIcon'] = true;
902
-						}
903
-					}
904
-				}
905
-				$info['version'] = OC_App::getAppVersion($app);
906
-				$appList[] = $info;
907
-			}
908
-		}
909
-		if ($onlyLocal) {
910
-			$remoteApps = [];
911
-		} else {
912
-			$remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
913
-		}
914
-		if ($remoteApps) {
915
-			// Remove duplicates
916
-			foreach ($appList as $app) {
917
-				foreach ($remoteApps AS $key => $remote) {
918
-					if ($app['name'] === $remote['name'] ||
919
-						(isset($app['ocsid']) &&
920
-							$app['ocsid'] === $remote['id'])
921
-					) {
922
-						unset($remoteApps[$key]);
923
-					}
924
-				}
925
-			}
926
-			$combinedApps = array_merge($appList, $remoteApps);
927
-		} else {
928
-			$combinedApps = $appList;
929
-		}
930
-
931
-		return $combinedApps;
932
-	}
933
-
934
-	/**
935
-	 * Returns the internal app ID or false
936
-	 * @param string $ocsID
937
-	 * @return string|false
938
-	 */
939
-	public static function getInternalAppIdByOcs($ocsID) {
940
-		if(is_numeric($ocsID)) {
941
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
942
-			if(array_search($ocsID, $idArray)) {
943
-				return array_search($ocsID, $idArray);
944
-			}
945
-		}
946
-		return false;
947
-	}
948
-
949
-	/**
950
-	 * Get a list of all apps on the appstore
951
-	 * @param string $filter
952
-	 * @param string|null $category
953
-	 * @param OCSClient $ocsClient
954
-	 * @return array|bool  multi-dimensional array of apps.
955
-	 *                     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
956
-	 */
957
-	public static function getAppstoreApps($filter = 'approved',
958
-										   $category = null,
959
-										   OCSClient $ocsClient) {
960
-		$categories = [$category];
961
-
962
-		if (is_null($category)) {
963
-			$categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
964
-			if (is_array($categoryNames)) {
965
-				// Check that categories of apps were retrieved correctly
966
-				if (!$categories = array_keys($categoryNames)) {
967
-					return false;
968
-				}
969
-			} else {
970
-				return false;
971
-			}
972
-		}
973
-
974
-		$page = 0;
975
-		$remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
976
-		$apps = [];
977
-		$i = 0;
978
-		$l = \OC::$server->getL10N('core');
979
-		foreach ($remoteApps as $app) {
980
-			$potentialCleanId = self::getInternalAppIdByOcs($app['id']);
981
-			// enhance app info (for example the description)
982
-			$apps[$i] = OC_App::parseAppInfo($app);
983
-			$apps[$i]['author'] = $app['personid'];
984
-			$apps[$i]['ocs_id'] = $app['id'];
985
-			$apps[$i]['internal'] = 0;
986
-			$apps[$i]['active'] = ($potentialCleanId !== false) ? self::isEnabled($potentialCleanId) : false;
987
-			$apps[$i]['update'] = false;
988
-			$apps[$i]['groups'] = false;
989
-			$apps[$i]['score'] = $app['score'];
990
-			$apps[$i]['removable'] = false;
991
-			if ($app['label'] == 'recommended') {
992
-				$apps[$i]['internallabel'] = (string)$l->t('Recommended');
993
-				$apps[$i]['internalclass'] = 'recommendedapp';
994
-			}
995
-
996
-			// Apps from the appstore are always assumed to be compatible with the
997
-			// the current release as the initial filtering is done on the appstore
998
-			$apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
999
-			$apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
1000
-
1001
-			$i++;
1002
-		}
1003
-
1004
-
1005
-
1006
-		if (empty($apps)) {
1007
-			return false;
1008
-		} else {
1009
-			return $apps;
1010
-		}
1011
-	}
1012
-
1013
-	public static function shouldUpgrade($app) {
1014
-		$versions = self::getAppVersions();
1015
-		$currentVersion = OC_App::getAppVersion($app);
1016
-		if ($currentVersion && isset($versions[$app])) {
1017
-			$installedVersion = $versions[$app];
1018
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
1019
-				return true;
1020
-			}
1021
-		}
1022
-		return false;
1023
-	}
1024
-
1025
-	/**
1026
-	 * Adjust the number of version parts of $version1 to match
1027
-	 * the number of version parts of $version2.
1028
-	 *
1029
-	 * @param string $version1 version to adjust
1030
-	 * @param string $version2 version to take the number of parts from
1031
-	 * @return string shortened $version1
1032
-	 */
1033
-	private static function adjustVersionParts($version1, $version2) {
1034
-		$version1 = explode('.', $version1);
1035
-		$version2 = explode('.', $version2);
1036
-		// reduce $version1 to match the number of parts in $version2
1037
-		while (count($version1) > count($version2)) {
1038
-			array_pop($version1);
1039
-		}
1040
-		// if $version1 does not have enough parts, add some
1041
-		while (count($version1) < count($version2)) {
1042
-			$version1[] = '0';
1043
-		}
1044
-		return implode('.', $version1);
1045
-	}
1046
-
1047
-	/**
1048
-	 * Check whether the current ownCloud version matches the given
1049
-	 * application's version requirements.
1050
-	 *
1051
-	 * The comparison is made based on the number of parts that the
1052
-	 * app info version has. For example for ownCloud 6.0.3 if the
1053
-	 * app info version is expecting version 6.0, the comparison is
1054
-	 * made on the first two parts of the ownCloud version.
1055
-	 * This means that it's possible to specify "requiremin" => 6
1056
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
1057
-	 *
1058
-	 * @param string $ocVersion ownCloud version to check against
1059
-	 * @param array $appInfo app info (from xml)
1060
-	 *
1061
-	 * @return boolean true if compatible, otherwise false
1062
-	 */
1063
-	public static function isAppCompatible($ocVersion, $appInfo) {
1064
-		$requireMin = '';
1065
-		$requireMax = '';
1066
-		if (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1067
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1068
-		} else if (isset($appInfo['requiremin'])) {
1069
-			$requireMin = $appInfo['requiremin'];
1070
-		} else if (isset($appInfo['require'])) {
1071
-			$requireMin = $appInfo['require'];
1072
-		}
1073
-
1074
-		if (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1075
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1076
-		} else if (isset($appInfo['requiremax'])) {
1077
-			$requireMax = $appInfo['requiremax'];
1078
-		}
1079
-
1080
-		if (is_array($ocVersion)) {
1081
-			$ocVersion = implode('.', $ocVersion);
1082
-		}
1083
-
1084
-		if (!empty($requireMin)
1085
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1086
-		) {
1087
-
1088
-			return false;
1089
-		}
1090
-
1091
-		if (!empty($requireMax)
1092
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1093
-		) {
1094
-			return false;
1095
-		}
1096
-
1097
-		return true;
1098
-	}
1099
-
1100
-	/**
1101
-	 * get the installed version of all apps
1102
-	 */
1103
-	public static function getAppVersions() {
1104
-		static $versions;
1105
-
1106
-		if(!$versions) {
1107
-			$appConfig = \OC::$server->getAppConfig();
1108
-			$versions = $appConfig->getValues(false, 'installed_version');
1109
-		}
1110
-		return $versions;
1111
-	}
1112
-
1113
-	/**
1114
-	 * @param string $app
1115
-	 * @return bool
1116
-	 * @throws Exception if app is not compatible with this version of ownCloud
1117
-	 * @throws Exception if no app-name was specified
1118
-	 */
1119
-	public static function installApp($app) {
1120
-		$appName = $app; // $app will be overwritten, preserve name for error logging
1121
-		$l = \OC::$server->getL10N('core');
1122
-		$config = \OC::$server->getConfig();
1123
-		$ocsClient = new OCSClient(
1124
-			\OC::$server->getHTTPClientService(),
1125
-			$config,
1126
-			\OC::$server->getLogger()
1127
-		);
1128
-		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
1129
-
1130
-		// check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
1131
-		if (!is_numeric($app)) {
1132
-			$shippedVersion = self::getAppVersion($app);
1133
-			if ($appData && version_compare($shippedVersion, $appData['version'], '<')) {
1134
-				$app = self::downloadApp($app);
1135
-			} else {
1136
-				$app = Installer::installShippedApp($app);
1137
-			}
1138
-		} else {
1139
-			// Maybe the app is already installed - compare the version in this
1140
-			// case and use the local already installed one.
1141
-			// FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1142
-			$internalAppId = self::getInternalAppIdByOcs($app);
1143
-			if($internalAppId !== false) {
1144
-				if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1145
-					$app = self::downloadApp($app);
1146
-				} else {
1147
-					self::enable($internalAppId);
1148
-					$app = $internalAppId;
1149
-				}
1150
-			} else {
1151
-				$app = self::downloadApp($app);
1152
-			}
1153
-		}
1154
-
1155
-		if ($app !== false) {
1156
-			// check if the app is compatible with this version of ownCloud
1157
-			$info = self::getAppInfo($app);
1158
-			if(!is_array($info)) {
1159
-				throw new \Exception(
1160
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1161
-						[$info['name']]
1162
-					)
1163
-				);
1164
-			}
1165
-
1166
-			$version = \OCP\Util::getVersion();
1167
-			if (!self::isAppCompatible($version, $info)) {
1168
-				throw new \Exception(
1169
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1170
-						array($info['name'])
1171
-					)
1172
-				);
1173
-			}
1174
-
1175
-			// check for required dependencies
1176
-			$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1177
-			$missing = $dependencyAnalyzer->analyze($info);
1178
-			if (!empty($missing)) {
1179
-				$missingMsg = join(PHP_EOL, $missing);
1180
-				throw new \Exception(
1181
-					$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1182
-						array($info['name'], $missingMsg)
1183
-					)
1184
-				);
1185
-			}
1186
-
1187
-			$config->setAppValue($app, 'enabled', 'yes');
1188
-			if (isset($appData['id'])) {
1189
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1190
-			}
1191
-
1192
-			if(isset($info['settings']) && is_array($info['settings'])) {
1193
-				$appPath = self::getAppPath($app);
1194
-				self::registerAutoloading($app, $appPath);
1195
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1196
-			}
1197
-
1198
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1199
-		} else {
1200
-			if(empty($appName) ) {
1201
-				throw new \Exception($l->t("No app name specified"));
1202
-			} else {
1203
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1204
-			}
1205
-		}
1206
-
1207
-		return $app;
1208
-	}
1209
-
1210
-	/**
1211
-	 * update the database for the app and call the update script
1212
-	 *
1213
-	 * @param string $appId
1214
-	 * @return bool
1215
-	 */
1216
-	public static function updateApp($appId) {
1217
-		$appPath = self::getAppPath($appId);
1218
-		if($appPath === false) {
1219
-			return false;
1220
-		}
1221
-		$appData = self::getAppInfo($appId);
1222
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1223
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1224
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1225
-		}
1226
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1227
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1228
-		unset(self::$appVersion[$appId]);
1229
-		// run upgrade code
1230
-		if (file_exists($appPath . '/appinfo/update.php')) {
1231
-			self::loadApp($appId, false);
1232
-			include $appPath . '/appinfo/update.php';
1233
-		}
1234
-		self::setupBackgroundJobs($appData['background-jobs']);
1235
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1236
-			$appPath = self::getAppPath($appId);
1237
-			self::registerAutoloading($appId, $appPath);
1238
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1239
-		}
1240
-
1241
-		//set remote/public handlers
1242
-		if (array_key_exists('ocsid', $appData)) {
1243
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1244
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1245
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1246
-		}
1247
-		foreach ($appData['remote'] as $name => $path) {
1248
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1249
-		}
1250
-		foreach ($appData['public'] as $name => $path) {
1251
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1252
-		}
1253
-
1254
-		self::setAppTypes($appId);
1255
-
1256
-		$version = \OC_App::getAppVersion($appId);
1257
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1258
-
1259
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1260
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1261
-		));
1262
-
1263
-		return true;
1264
-	}
1265
-
1266
-	/**
1267
-	 * @param string $appId
1268
-	 * @param string[] $steps
1269
-	 * @throws \OC\NeedsUpdateException
1270
-	 */
1271
-	public static function executeRepairSteps($appId, array $steps) {
1272
-		if (empty($steps)) {
1273
-			return;
1274
-		}
1275
-		// load the app
1276
-		self::loadApp($appId, false);
1277
-
1278
-		$dispatcher = OC::$server->getEventDispatcher();
1279
-
1280
-		// load the steps
1281
-		$r = new Repair([], $dispatcher);
1282
-		foreach ($steps as $step) {
1283
-			try {
1284
-				$r->addStep($step);
1285
-			} catch (Exception $ex) {
1286
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1287
-				\OC::$server->getLogger()->logException($ex);
1288
-			}
1289
-		}
1290
-		// run the steps
1291
-		$r->run();
1292
-	}
1293
-
1294
-	public static function setupBackgroundJobs(array $jobs) {
1295
-		$queue = \OC::$server->getJobList();
1296
-		foreach ($jobs as $job) {
1297
-			$queue->add($job);
1298
-		}
1299
-	}
1300
-
1301
-	/**
1302
-	 * @param string $appId
1303
-	 * @param string[] $steps
1304
-	 */
1305
-	private static function setupLiveMigrations($appId, array $steps) {
1306
-		$queue = \OC::$server->getJobList();
1307
-		foreach ($steps as $step) {
1308
-			$queue->add('OC\Migration\BackgroundRepair', [
1309
-				'app' => $appId,
1310
-				'step' => $step]);
1311
-		}
1312
-	}
1313
-
1314
-	/**
1315
-	 * @param string $appId
1316
-	 * @return \OC\Files\View|false
1317
-	 */
1318
-	public static function getStorage($appId) {
1319
-		if (OC_App::isEnabled($appId)) { //sanity check
1320
-			if (OC_User::isLoggedIn()) {
1321
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1322
-				if (!$view->file_exists($appId)) {
1323
-					$view->mkdir($appId);
1324
-				}
1325
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1326
-			} else {
1327
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1328
-				return false;
1329
-			}
1330
-		} else {
1331
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1332
-			return false;
1333
-		}
1334
-	}
1335
-
1336
-	protected static function findBestL10NOption($options, $lang) {
1337
-		$fallback = $similarLangFallback = $englishFallback = false;
1338
-
1339
-		$lang = strtolower($lang);
1340
-		$similarLang = $lang;
1341
-		if (strpos($similarLang, '_')) {
1342
-			// For "de_DE" we want to find "de" and the other way around
1343
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1344
-		}
1345
-
1346
-		foreach ($options as $option) {
1347
-			if (is_array($option)) {
1348
-				if ($fallback === false) {
1349
-					$fallback = $option['@value'];
1350
-				}
1351
-
1352
-				if (!isset($option['@attributes']['lang'])) {
1353
-					continue;
1354
-				}
1355
-
1356
-				$attributeLang = strtolower($option['@attributes']['lang']);
1357
-				if ($attributeLang === $lang) {
1358
-					return $option['@value'];
1359
-				}
1360
-
1361
-				if ($attributeLang === $similarLang) {
1362
-					$similarLangFallback = $option['@value'];
1363
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1364
-					if ($similarLangFallback === false) {
1365
-						$similarLangFallback =  $option['@value'];
1366
-					}
1367
-				}
1368
-			} else {
1369
-				$englishFallback = $option;
1370
-			}
1371
-		}
1372
-
1373
-		if ($similarLangFallback !== false) {
1374
-			return $similarLangFallback;
1375
-		} else if ($englishFallback !== false) {
1376
-			return $englishFallback;
1377
-		}
1378
-		return (string) $fallback;
1379
-	}
1380
-
1381
-	/**
1382
-	 * parses the app data array and enhanced the 'description' value
1383
-	 *
1384
-	 * @param array $data the app data
1385
-	 * @param string $lang
1386
-	 * @return array improved app data
1387
-	 */
1388
-	public static function parseAppInfo(array $data, $lang = null) {
1389
-
1390
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1391
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1392
-		}
1393
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1394
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1395
-		}
1396
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1397
-			$data['description'] = self::findBestL10NOption($data['description'], $lang);
1398
-		}
1399
-
1400
-		// just modify the description if it is available
1401
-		// otherwise this will create a $data element with an empty 'description'
1402
-		if (isset($data['description'])) {
1403
-			if (is_string($data['description'])) {
1404
-				// sometimes the description contains line breaks and they are then also
1405
-				// shown in this way in the app management which isn't wanted as HTML
1406
-				// manages line breaks itself
1407
-
1408
-				// first of all we split on empty lines
1409
-				$paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']);
1410
-
1411
-				$result = [];
1412
-				foreach ($paragraphs as $value) {
1413
-					// replace multiple whitespace (tabs, space, newlines) inside a paragraph
1414
-					// with a single space - also trims whitespace
1415
-					$result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value));
1416
-				}
1417
-
1418
-				// join the single paragraphs with a empty line in between
1419
-				$data['description'] = implode("\n\n", $result);
1420
-
1421
-			} else {
1422
-				$data['description'] = '';
1423
-			}
1424
-		}
1425
-
1426
-		return $data;
1427
-	}
62
+    static private $appVersion = [];
63
+    static private $adminForms = array();
64
+    static private $personalForms = array();
65
+    static private $appInfo = array();
66
+    static private $appTypes = array();
67
+    static private $loadedApps = array();
68
+    static private $altLogin = array();
69
+    static private $alreadyRegistered = [];
70
+    const officialApp = 200;
71
+
72
+    /**
73
+     * clean the appId
74
+     *
75
+     * @param string|boolean $app AppId that needs to be cleaned
76
+     * @return string
77
+     */
78
+    public static function cleanAppId($app) {
79
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
80
+    }
81
+
82
+    /**
83
+     * Check if an app is loaded
84
+     *
85
+     * @param string $app
86
+     * @return bool
87
+     */
88
+    public static function isAppLoaded($app) {
89
+        return in_array($app, self::$loadedApps, true);
90
+    }
91
+
92
+    /**
93
+     * loads all apps
94
+     *
95
+     * @param string[] | string | null $types
96
+     * @return bool
97
+     *
98
+     * This function walks through the ownCloud directory and loads all apps
99
+     * it can find. A directory contains an app if the file /appinfo/info.xml
100
+     * exists.
101
+     *
102
+     * if $types is set, only apps of those types will be loaded
103
+     */
104
+    public static function loadApps($types = null) {
105
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
106
+            return false;
107
+        }
108
+        // Load the enabled apps here
109
+        $apps = self::getEnabledApps();
110
+
111
+        // Add each apps' folder as allowed class path
112
+        foreach($apps as $app) {
113
+            $path = self::getAppPath($app);
114
+            if($path !== false) {
115
+                self::registerAutoloading($app, $path);
116
+            }
117
+        }
118
+
119
+        // prevent app.php from printing output
120
+        ob_start();
121
+        foreach ($apps as $app) {
122
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
123
+                self::loadApp($app);
124
+            }
125
+        }
126
+        ob_end_clean();
127
+
128
+        return true;
129
+    }
130
+
131
+    /**
132
+     * load a single app
133
+     *
134
+     * @param string $app
135
+     * @param bool $checkUpgrade whether an upgrade check should be done
136
+     * @throws \OC\NeedsUpdateException
137
+     */
138
+    public static function loadApp($app, $checkUpgrade = true) {
139
+        self::$loadedApps[] = $app;
140
+        $appPath = self::getAppPath($app);
141
+        if($appPath === false) {
142
+            return;
143
+        }
144
+
145
+        // in case someone calls loadApp() directly
146
+        self::registerAutoloading($app, $appPath);
147
+
148
+        if (is_file($appPath . '/appinfo/app.php')) {
149
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
+            if ($checkUpgrade and self::shouldUpgrade($app)) {
151
+                throw new \OC\NeedsUpdateException();
152
+            }
153
+            self::requireAppFile($app);
154
+            if (self::isType($app, array('authentication'))) {
155
+                // since authentication apps affect the "is app enabled for group" check,
156
+                // the enabled apps cache needs to be cleared to make sure that the
157
+                // next time getEnableApps() is called it will also include apps that were
158
+                // enabled for groups
159
+                self::$enabledAppsCache = array();
160
+            }
161
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
162
+        }
163
+    }
164
+
165
+    /**
166
+     * @internal
167
+     * @param string $app
168
+     * @param string $path
169
+     */
170
+    public static function registerAutoloading($app, $path) {
171
+        $key = $app . '-' . $path;
172
+        if(isset(self::$alreadyRegistered[$key])) {
173
+            return;
174
+        }
175
+        self::$alreadyRegistered[$key] = true;
176
+        // Register on PSR-4 composer autoloader
177
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
178
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
179
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
180
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
181
+        }
182
+
183
+        // Register on legacy autoloader
184
+        \OC::$loader->addValidRoot($path);
185
+    }
186
+
187
+    /**
188
+     * Load app.php from the given app
189
+     *
190
+     * @param string $app app name
191
+     */
192
+    private static function requireAppFile($app) {
193
+        try {
194
+            // encapsulated here to avoid variable scope conflicts
195
+            require_once $app . '/appinfo/app.php';
196
+        } catch (Error $ex) {
197
+            \OC::$server->getLogger()->logException($ex);
198
+            $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
199
+            if (!in_array($app, $blacklist)) {
200
+                self::disable($app);
201
+            }
202
+        }
203
+    }
204
+
205
+    /**
206
+     * check if an app is of a specific type
207
+     *
208
+     * @param string $app
209
+     * @param string|array $types
210
+     * @return bool
211
+     */
212
+    public static function isType($app, $types) {
213
+        if (is_string($types)) {
214
+            $types = array($types);
215
+        }
216
+        $appTypes = self::getAppTypes($app);
217
+        foreach ($types as $type) {
218
+            if (array_search($type, $appTypes) !== false) {
219
+                return true;
220
+            }
221
+        }
222
+        return false;
223
+    }
224
+
225
+    /**
226
+     * get the types of an app
227
+     *
228
+     * @param string $app
229
+     * @return array
230
+     */
231
+    private static function getAppTypes($app) {
232
+        //load the cache
233
+        if (count(self::$appTypes) == 0) {
234
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
235
+        }
236
+
237
+        if (isset(self::$appTypes[$app])) {
238
+            return explode(',', self::$appTypes[$app]);
239
+        } else {
240
+            return array();
241
+        }
242
+    }
243
+
244
+    /**
245
+     * read app types from info.xml and cache them in the database
246
+     */
247
+    public static function setAppTypes($app) {
248
+        $appData = self::getAppInfo($app);
249
+        if(!is_array($appData)) {
250
+            return;
251
+        }
252
+
253
+        if (isset($appData['types'])) {
254
+            $appTypes = implode(',', $appData['types']);
255
+        } else {
256
+            $appTypes = '';
257
+        }
258
+
259
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
260
+    }
261
+
262
+    /**
263
+     * check if app is shipped
264
+     *
265
+     * @param string $appId the id of the app to check
266
+     * @return bool
267
+     *
268
+     * Check if an app that is installed is a shipped app or installed from the appstore.
269
+     */
270
+    public static function isShipped($appId) {
271
+        return \OC::$server->getAppManager()->isShipped($appId);
272
+    }
273
+
274
+    /**
275
+     * get all enabled apps
276
+     */
277
+    protected static $enabledAppsCache = array();
278
+
279
+    /**
280
+     * Returns apps enabled for the current user.
281
+     *
282
+     * @param bool $forceRefresh whether to refresh the cache
283
+     * @param bool $all whether to return apps for all users, not only the
284
+     * currently logged in one
285
+     * @return string[]
286
+     */
287
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
288
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
289
+            return array();
290
+        }
291
+        // in incognito mode or when logged out, $user will be false,
292
+        // which is also the case during an upgrade
293
+        $appManager = \OC::$server->getAppManager();
294
+        if ($all) {
295
+            $user = null;
296
+        } else {
297
+            $user = \OC::$server->getUserSession()->getUser();
298
+        }
299
+
300
+        if (is_null($user)) {
301
+            $apps = $appManager->getInstalledApps();
302
+        } else {
303
+            $apps = $appManager->getEnabledAppsForUser($user);
304
+        }
305
+        $apps = array_filter($apps, function ($app) {
306
+            return $app !== 'files';//we add this manually
307
+        });
308
+        sort($apps);
309
+        array_unshift($apps, 'files');
310
+        return $apps;
311
+    }
312
+
313
+    /**
314
+     * checks whether or not an app is enabled
315
+     *
316
+     * @param string $app app
317
+     * @return bool
318
+     *
319
+     * This function checks whether or not an app is enabled.
320
+     */
321
+    public static function isEnabled($app) {
322
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
323
+    }
324
+
325
+    /**
326
+     * enables an app
327
+     *
328
+     * @param mixed $app app
329
+     * @param array $groups (optional) when set, only these groups will have access to the app
330
+     * @throws \Exception
331
+     * @return void
332
+     *
333
+     * This function set an app as enabled in appconfig.
334
+     */
335
+    public static function enable($app, $groups = null) {
336
+        self::$enabledAppsCache = array(); // flush
337
+        if (!Installer::isInstalled($app)) {
338
+            $app = self::installApp($app);
339
+        }
340
+
341
+        $appManager = \OC::$server->getAppManager();
342
+        if (!is_null($groups)) {
343
+            $groupManager = \OC::$server->getGroupManager();
344
+            $groupsList = [];
345
+            foreach ($groups as $group) {
346
+                $groupItem = $groupManager->get($group);
347
+                if ($groupItem instanceof \OCP\IGroup) {
348
+                    $groupsList[] = $groupManager->get($group);
349
+                }
350
+            }
351
+            $appManager->enableAppForGroups($app, $groupsList);
352
+        } else {
353
+            $appManager->enableApp($app);
354
+        }
355
+
356
+        $info = self::getAppInfo($app);
357
+        if(isset($info['settings']) && is_array($info['settings'])) {
358
+            $appPath = self::getAppPath($app);
359
+            self::registerAutoloading($app, $appPath);
360
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
361
+        }
362
+    }
363
+
364
+    /**
365
+     * @param string $app
366
+     * @return int
367
+     */
368
+    private static function downloadApp($app) {
369
+        $ocsClient = new OCSClient(
370
+            \OC::$server->getHTTPClientService(),
371
+            \OC::$server->getConfig(),
372
+            \OC::$server->getLogger()
373
+        );
374
+        $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
375
+        $download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
376
+        if(isset($download['downloadlink']) and $download['downloadlink']!='') {
377
+            // Replace spaces in download link without encoding entire URL
378
+            $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
379
+            $info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
380
+            $app = Installer::installApp($info);
381
+        }
382
+        return $app;
383
+    }
384
+
385
+    /**
386
+     * @param string $app
387
+     * @return bool
388
+     */
389
+    public static function removeApp($app) {
390
+        if (self::isShipped($app)) {
391
+            return false;
392
+        }
393
+
394
+        return Installer::removeApp($app);
395
+    }
396
+
397
+    /**
398
+     * This function set an app as disabled in appconfig.
399
+     *
400
+     * @param string $app app
401
+     * @throws Exception
402
+     */
403
+    public static function disable($app) {
404
+        // Convert OCS ID to regular application identifier
405
+        if(self::getInternalAppIdByOcs($app) !== false) {
406
+            $app = self::getInternalAppIdByOcs($app);
407
+        }
408
+
409
+        // flush
410
+        self::$enabledAppsCache = array();
411
+
412
+        // run uninstall steps
413
+        $appData = OC_App::getAppInfo($app);
414
+        if (!is_null($appData)) {
415
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
416
+        }
417
+
418
+        // emit disable hook - needed anymore ?
419
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
420
+
421
+        // finally disable it
422
+        $appManager = \OC::$server->getAppManager();
423
+        $appManager->disableApp($app);
424
+    }
425
+
426
+    /**
427
+     * Returns the Settings Navigation
428
+     *
429
+     * @return string[]
430
+     *
431
+     * This function returns an array containing all settings pages added. The
432
+     * entries are sorted by the key 'order' ascending.
433
+     */
434
+    public static function getSettingsNavigation() {
435
+        $l = \OC::$server->getL10N('lib');
436
+        $urlGenerator = \OC::$server->getURLGenerator();
437
+
438
+        $settings = array();
439
+        // by default, settings only contain the help menu
440
+        if (OC_Util::getEditionString() === '' &&
441
+            \OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
442
+        ) {
443
+            $settings = array(
444
+                array(
445
+                    "id" => "help",
446
+                    "order" => 1000,
447
+                    "href" => $urlGenerator->linkToRoute('settings_help'),
448
+                    "name" => $l->t("Help"),
449
+                    "icon" => $urlGenerator->imagePath("settings", "help.svg")
450
+                )
451
+            );
452
+        }
453
+
454
+        // if the user is logged-in
455
+        if (OC_User::isLoggedIn()) {
456
+            // personal menu
457
+            $settings[] = array(
458
+                "id" => "personal",
459
+                "order" => 1,
460
+                "href" => $urlGenerator->linkToRoute('settings_personal'),
461
+                "name" => $l->t("Personal"),
462
+                "icon" => $urlGenerator->imagePath("settings", "personal.svg")
463
+            );
464
+
465
+            //SubAdmins are also allowed to access user management
466
+            $userObject = \OC::$server->getUserSession()->getUser();
467
+            $isSubAdmin = false;
468
+            if($userObject !== null) {
469
+                $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
470
+            }
471
+            if ($isSubAdmin) {
472
+                // admin users menu
473
+                $settings[] = array(
474
+                    "id" => "core_users",
475
+                    "order" => 2,
476
+                    "href" => $urlGenerator->linkToRoute('settings_users'),
477
+                    "name" => $l->t("Users"),
478
+                    "icon" => $urlGenerator->imagePath("settings", "users.svg")
479
+                );
480
+            }
481
+
482
+            // if the user is an admin
483
+            if (OC_User::isAdminUser(OC_User::getUser())) {
484
+                // admin settings
485
+                $settings[] = array(
486
+                    "id" => "admin",
487
+                    "order" => 1000,
488
+                    "href" => $urlGenerator->linkToRoute('settings.AdminSettings.index'),
489
+                    "name" => $l->t("Admin"),
490
+                    "icon" => $urlGenerator->imagePath("settings", "admin.svg")
491
+                );
492
+            }
493
+        }
494
+
495
+        $navigation = self::proceedNavigation($settings);
496
+        return $navigation;
497
+    }
498
+
499
+    // This is private as well. It simply works, so don't ask for more details
500
+    private static function proceedNavigation($list) {
501
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
502
+        foreach ($list as &$navEntry) {
503
+            if ($navEntry['id'] == $activeApp) {
504
+                $navEntry['active'] = true;
505
+            } else {
506
+                $navEntry['active'] = false;
507
+            }
508
+        }
509
+        unset($navEntry);
510
+
511
+        usort($list, function($a, $b) {
512
+            if (isset($a['order']) && isset($b['order'])) {
513
+                return ($a['order'] < $b['order']) ? -1 : 1;
514
+            } else if (isset($a['order']) || isset($b['order'])) {
515
+                return isset($a['order']) ? -1 : 1;
516
+            } else {
517
+                return ($a['name'] < $b['name']) ? -1 : 1;
518
+            }
519
+        });
520
+
521
+        return $list;
522
+    }
523
+
524
+    /**
525
+     * Get the path where to install apps
526
+     *
527
+     * @return string|false
528
+     */
529
+    public static function getInstallPath() {
530
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
531
+            return false;
532
+        }
533
+
534
+        foreach (OC::$APPSROOTS as $dir) {
535
+            if (isset($dir['writable']) && $dir['writable'] === true) {
536
+                return $dir['path'];
537
+            }
538
+        }
539
+
540
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
541
+        return null;
542
+    }
543
+
544
+
545
+    /**
546
+     * search for an app in all app-directories
547
+     *
548
+     * @param string $appId
549
+     * @return false|string
550
+     */
551
+    protected static function findAppInDirectories($appId) {
552
+        $sanitizedAppId = self::cleanAppId($appId);
553
+        if($sanitizedAppId !== $appId) {
554
+            return false;
555
+        }
556
+        static $app_dir = array();
557
+
558
+        if (isset($app_dir[$appId])) {
559
+            return $app_dir[$appId];
560
+        }
561
+
562
+        $possibleApps = array();
563
+        foreach (OC::$APPSROOTS as $dir) {
564
+            if (file_exists($dir['path'] . '/' . $appId)) {
565
+                $possibleApps[] = $dir;
566
+            }
567
+        }
568
+
569
+        if (empty($possibleApps)) {
570
+            return false;
571
+        } elseif (count($possibleApps) === 1) {
572
+            $dir = array_shift($possibleApps);
573
+            $app_dir[$appId] = $dir;
574
+            return $dir;
575
+        } else {
576
+            $versionToLoad = array();
577
+            foreach ($possibleApps as $possibleApp) {
578
+                $version = self::getAppVersionByPath($possibleApp['path']);
579
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
580
+                    $versionToLoad = array(
581
+                        'dir' => $possibleApp,
582
+                        'version' => $version,
583
+                    );
584
+                }
585
+            }
586
+            $app_dir[$appId] = $versionToLoad['dir'];
587
+            return $versionToLoad['dir'];
588
+            //TODO - write test
589
+        }
590
+    }
591
+
592
+    /**
593
+     * Get the directory for the given app.
594
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
595
+     *
596
+     * @param string $appId
597
+     * @return string|false
598
+     */
599
+    public static function getAppPath($appId) {
600
+        if ($appId === null || trim($appId) === '') {
601
+            return false;
602
+        }
603
+
604
+        if (($dir = self::findAppInDirectories($appId)) != false) {
605
+            return $dir['path'] . '/' . $appId;
606
+        }
607
+        return false;
608
+    }
609
+
610
+
611
+    /**
612
+     * check if an app's directory is writable
613
+     *
614
+     * @param string $appId
615
+     * @return bool
616
+     */
617
+    public static function isAppDirWritable($appId) {
618
+        $path = self::getAppPath($appId);
619
+        return ($path !== false) ? is_writable($path) : false;
620
+    }
621
+
622
+    /**
623
+     * Get the path for the given app on the access
624
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
625
+     *
626
+     * @param string $appId
627
+     * @return string|false
628
+     */
629
+    public static function getAppWebPath($appId) {
630
+        if (($dir = self::findAppInDirectories($appId)) != false) {
631
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
632
+        }
633
+        return false;
634
+    }
635
+
636
+    /**
637
+     * get the last version of the app from appinfo/info.xml
638
+     *
639
+     * @param string $appId
640
+     * @return string
641
+     */
642
+    public static function getAppVersion($appId) {
643
+        if (!isset(self::$appVersion[$appId])) {
644
+            $file = self::getAppPath($appId);
645
+            self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
646
+        }
647
+        return self::$appVersion[$appId];
648
+    }
649
+
650
+    /**
651
+     * get app's version based on it's path
652
+     *
653
+     * @param string $path
654
+     * @return string
655
+     */
656
+    public static function getAppVersionByPath($path) {
657
+        $infoFile = $path . '/appinfo/info.xml';
658
+        $appData = self::getAppInfo($infoFile, true);
659
+        return isset($appData['version']) ? $appData['version'] : '';
660
+    }
661
+
662
+
663
+    /**
664
+     * Read all app metadata from the info.xml file
665
+     *
666
+     * @param string $appId id of the app or the path of the info.xml file
667
+     * @param bool $path
668
+     * @param string $lang
669
+     * @return array|null
670
+     * @note all data is read from info.xml, not just pre-defined fields
671
+     */
672
+    public static function getAppInfo($appId, $path = false, $lang = null) {
673
+        if ($path) {
674
+            $file = $appId;
675
+        } else {
676
+            if ($lang === null && isset(self::$appInfo[$appId])) {
677
+                return self::$appInfo[$appId];
678
+            }
679
+            $appPath = self::getAppPath($appId);
680
+            if($appPath === false) {
681
+                return null;
682
+            }
683
+            $file = $appPath . '/appinfo/info.xml';
684
+        }
685
+
686
+        $parser = new \OC\App\InfoParser(\OC::$server->getURLGenerator());
687
+        $data = $parser->parse($file);
688
+
689
+        if (is_array($data)) {
690
+            $data = OC_App::parseAppInfo($data, $lang);
691
+        }
692
+        if(isset($data['ocsid'])) {
693
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
694
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
695
+                $data['ocsid'] = $storedId;
696
+            }
697
+        }
698
+
699
+        if ($lang === null) {
700
+            self::$appInfo[$appId] = $data;
701
+        }
702
+
703
+        return $data;
704
+    }
705
+
706
+    /**
707
+     * Returns the navigation
708
+     *
709
+     * @return array
710
+     *
711
+     * This function returns an array containing all entries added. The
712
+     * entries are sorted by the key 'order' ascending. Additional to the keys
713
+     * given for each app the following keys exist:
714
+     *   - active: boolean, signals if the user is on this navigation entry
715
+     */
716
+    public static function getNavigation() {
717
+        $entries = OC::$server->getNavigationManager()->getAll();
718
+        $navigation = self::proceedNavigation($entries);
719
+        return $navigation;
720
+    }
721
+
722
+    /**
723
+     * get the id of loaded app
724
+     *
725
+     * @return string
726
+     */
727
+    public static function getCurrentApp() {
728
+        $request = \OC::$server->getRequest();
729
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
730
+        $topFolder = substr($script, 0, strpos($script, '/'));
731
+        if (empty($topFolder)) {
732
+            $path_info = $request->getPathInfo();
733
+            if ($path_info) {
734
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
735
+            }
736
+        }
737
+        if ($topFolder == 'apps') {
738
+            $length = strlen($topFolder);
739
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
740
+        } else {
741
+            return $topFolder;
742
+        }
743
+    }
744
+
745
+    /**
746
+     * @param string $type
747
+     * @return array
748
+     */
749
+    public static function getForms($type) {
750
+        $forms = array();
751
+        switch ($type) {
752
+            case 'admin':
753
+                $source = self::$adminForms;
754
+                break;
755
+            case 'personal':
756
+                $source = self::$personalForms;
757
+                break;
758
+            default:
759
+                return array();
760
+        }
761
+        foreach ($source as $form) {
762
+            $forms[] = include $form;
763
+        }
764
+        return $forms;
765
+    }
766
+
767
+    /**
768
+     * register an admin form to be shown
769
+     *
770
+     * @param string $app
771
+     * @param string $page
772
+     */
773
+    public static function registerAdmin($app, $page) {
774
+        self::$adminForms[] = $app . '/' . $page . '.php';
775
+    }
776
+
777
+    /**
778
+     * register a personal form to be shown
779
+     * @param string $app
780
+     * @param string $page
781
+     */
782
+    public static function registerPersonal($app, $page) {
783
+        self::$personalForms[] = $app . '/' . $page . '.php';
784
+    }
785
+
786
+    /**
787
+     * @param array $entry
788
+     */
789
+    public static function registerLogIn(array $entry) {
790
+        self::$altLogin[] = $entry;
791
+    }
792
+
793
+    /**
794
+     * @return array
795
+     */
796
+    public static function getAlternativeLogIns() {
797
+        return self::$altLogin;
798
+    }
799
+
800
+    /**
801
+     * get a list of all apps in the apps folder
802
+     *
803
+     * @return array an array of app names (string IDs)
804
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
805
+     */
806
+    public static function getAllApps() {
807
+
808
+        $apps = array();
809
+
810
+        foreach (OC::$APPSROOTS as $apps_dir) {
811
+            if (!is_readable($apps_dir['path'])) {
812
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
813
+                continue;
814
+            }
815
+            $dh = opendir($apps_dir['path']);
816
+
817
+            if (is_resource($dh)) {
818
+                while (($file = readdir($dh)) !== false) {
819
+
820
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
821
+
822
+                        $apps[] = $file;
823
+                    }
824
+                }
825
+            }
826
+        }
827
+
828
+        return $apps;
829
+    }
830
+
831
+    /**
832
+     * List all apps, this is used in apps.php
833
+     *
834
+     * @param bool $onlyLocal
835
+     * @param bool $includeUpdateInfo Should we check whether there is an update
836
+     *                                in the app store?
837
+     * @param OCSClient $ocsClient
838
+     * @return array
839
+     */
840
+    public static function listAllApps($onlyLocal = false,
841
+                                        $includeUpdateInfo = true,
842
+                                        OCSClient $ocsClient) {
843
+        $installedApps = OC_App::getAllApps();
844
+
845
+        //TODO which apps do we want to blacklist and how do we integrate
846
+        // blacklisting with the multi apps folder feature?
847
+
848
+        //we don't want to show configuration for these
849
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
850
+        $appList = array();
851
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
852
+
853
+        foreach ($installedApps as $app) {
854
+            if (array_search($app, $blacklist) === false) {
855
+
856
+                $info = OC_App::getAppInfo($app, false, $langCode);
857
+                if (!is_array($info)) {
858
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
859
+                    continue;
860
+                }
861
+
862
+                if (!isset($info['name'])) {
863
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
864
+                    continue;
865
+                }
866
+
867
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
868
+                $info['groups'] = null;
869
+                if ($enabled === 'yes') {
870
+                    $active = true;
871
+                } else if ($enabled === 'no') {
872
+                    $active = false;
873
+                } else {
874
+                    $active = true;
875
+                    $info['groups'] = $enabled;
876
+                }
877
+
878
+                $info['active'] = $active;
879
+
880
+                if (self::isShipped($app)) {
881
+                    $info['internal'] = true;
882
+                    $info['level'] = self::officialApp;
883
+                    $info['removable'] = false;
884
+                } else {
885
+                    $info['internal'] = false;
886
+                    $info['removable'] = true;
887
+                }
888
+
889
+                $info['update'] = ($includeUpdateInfo) ? Installer::isUpdateAvailable($app) : null;
890
+
891
+                $appPath = self::getAppPath($app);
892
+                if($appPath !== false) {
893
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
894
+                    if (file_exists($appIcon)) {
895
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
896
+                        $info['previewAsIcon'] = true;
897
+                    } else {
898
+                        $appIcon = $appPath . '/img/app.svg';
899
+                        if (file_exists($appIcon)) {
900
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
901
+                            $info['previewAsIcon'] = true;
902
+                        }
903
+                    }
904
+                }
905
+                $info['version'] = OC_App::getAppVersion($app);
906
+                $appList[] = $info;
907
+            }
908
+        }
909
+        if ($onlyLocal) {
910
+            $remoteApps = [];
911
+        } else {
912
+            $remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
913
+        }
914
+        if ($remoteApps) {
915
+            // Remove duplicates
916
+            foreach ($appList as $app) {
917
+                foreach ($remoteApps AS $key => $remote) {
918
+                    if ($app['name'] === $remote['name'] ||
919
+                        (isset($app['ocsid']) &&
920
+                            $app['ocsid'] === $remote['id'])
921
+                    ) {
922
+                        unset($remoteApps[$key]);
923
+                    }
924
+                }
925
+            }
926
+            $combinedApps = array_merge($appList, $remoteApps);
927
+        } else {
928
+            $combinedApps = $appList;
929
+        }
930
+
931
+        return $combinedApps;
932
+    }
933
+
934
+    /**
935
+     * Returns the internal app ID or false
936
+     * @param string $ocsID
937
+     * @return string|false
938
+     */
939
+    public static function getInternalAppIdByOcs($ocsID) {
940
+        if(is_numeric($ocsID)) {
941
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
942
+            if(array_search($ocsID, $idArray)) {
943
+                return array_search($ocsID, $idArray);
944
+            }
945
+        }
946
+        return false;
947
+    }
948
+
949
+    /**
950
+     * Get a list of all apps on the appstore
951
+     * @param string $filter
952
+     * @param string|null $category
953
+     * @param OCSClient $ocsClient
954
+     * @return array|bool  multi-dimensional array of apps.
955
+     *                     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
956
+     */
957
+    public static function getAppstoreApps($filter = 'approved',
958
+                                            $category = null,
959
+                                            OCSClient $ocsClient) {
960
+        $categories = [$category];
961
+
962
+        if (is_null($category)) {
963
+            $categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
964
+            if (is_array($categoryNames)) {
965
+                // Check that categories of apps were retrieved correctly
966
+                if (!$categories = array_keys($categoryNames)) {
967
+                    return false;
968
+                }
969
+            } else {
970
+                return false;
971
+            }
972
+        }
973
+
974
+        $page = 0;
975
+        $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
976
+        $apps = [];
977
+        $i = 0;
978
+        $l = \OC::$server->getL10N('core');
979
+        foreach ($remoteApps as $app) {
980
+            $potentialCleanId = self::getInternalAppIdByOcs($app['id']);
981
+            // enhance app info (for example the description)
982
+            $apps[$i] = OC_App::parseAppInfo($app);
983
+            $apps[$i]['author'] = $app['personid'];
984
+            $apps[$i]['ocs_id'] = $app['id'];
985
+            $apps[$i]['internal'] = 0;
986
+            $apps[$i]['active'] = ($potentialCleanId !== false) ? self::isEnabled($potentialCleanId) : false;
987
+            $apps[$i]['update'] = false;
988
+            $apps[$i]['groups'] = false;
989
+            $apps[$i]['score'] = $app['score'];
990
+            $apps[$i]['removable'] = false;
991
+            if ($app['label'] == 'recommended') {
992
+                $apps[$i]['internallabel'] = (string)$l->t('Recommended');
993
+                $apps[$i]['internalclass'] = 'recommendedapp';
994
+            }
995
+
996
+            // Apps from the appstore are always assumed to be compatible with the
997
+            // the current release as the initial filtering is done on the appstore
998
+            $apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
999
+            $apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
1000
+
1001
+            $i++;
1002
+        }
1003
+
1004
+
1005
+
1006
+        if (empty($apps)) {
1007
+            return false;
1008
+        } else {
1009
+            return $apps;
1010
+        }
1011
+    }
1012
+
1013
+    public static function shouldUpgrade($app) {
1014
+        $versions = self::getAppVersions();
1015
+        $currentVersion = OC_App::getAppVersion($app);
1016
+        if ($currentVersion && isset($versions[$app])) {
1017
+            $installedVersion = $versions[$app];
1018
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
1019
+                return true;
1020
+            }
1021
+        }
1022
+        return false;
1023
+    }
1024
+
1025
+    /**
1026
+     * Adjust the number of version parts of $version1 to match
1027
+     * the number of version parts of $version2.
1028
+     *
1029
+     * @param string $version1 version to adjust
1030
+     * @param string $version2 version to take the number of parts from
1031
+     * @return string shortened $version1
1032
+     */
1033
+    private static function adjustVersionParts($version1, $version2) {
1034
+        $version1 = explode('.', $version1);
1035
+        $version2 = explode('.', $version2);
1036
+        // reduce $version1 to match the number of parts in $version2
1037
+        while (count($version1) > count($version2)) {
1038
+            array_pop($version1);
1039
+        }
1040
+        // if $version1 does not have enough parts, add some
1041
+        while (count($version1) < count($version2)) {
1042
+            $version1[] = '0';
1043
+        }
1044
+        return implode('.', $version1);
1045
+    }
1046
+
1047
+    /**
1048
+     * Check whether the current ownCloud version matches the given
1049
+     * application's version requirements.
1050
+     *
1051
+     * The comparison is made based on the number of parts that the
1052
+     * app info version has. For example for ownCloud 6.0.3 if the
1053
+     * app info version is expecting version 6.0, the comparison is
1054
+     * made on the first two parts of the ownCloud version.
1055
+     * This means that it's possible to specify "requiremin" => 6
1056
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
1057
+     *
1058
+     * @param string $ocVersion ownCloud version to check against
1059
+     * @param array $appInfo app info (from xml)
1060
+     *
1061
+     * @return boolean true if compatible, otherwise false
1062
+     */
1063
+    public static function isAppCompatible($ocVersion, $appInfo) {
1064
+        $requireMin = '';
1065
+        $requireMax = '';
1066
+        if (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1067
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1068
+        } else if (isset($appInfo['requiremin'])) {
1069
+            $requireMin = $appInfo['requiremin'];
1070
+        } else if (isset($appInfo['require'])) {
1071
+            $requireMin = $appInfo['require'];
1072
+        }
1073
+
1074
+        if (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1075
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1076
+        } else if (isset($appInfo['requiremax'])) {
1077
+            $requireMax = $appInfo['requiremax'];
1078
+        }
1079
+
1080
+        if (is_array($ocVersion)) {
1081
+            $ocVersion = implode('.', $ocVersion);
1082
+        }
1083
+
1084
+        if (!empty($requireMin)
1085
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1086
+        ) {
1087
+
1088
+            return false;
1089
+        }
1090
+
1091
+        if (!empty($requireMax)
1092
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1093
+        ) {
1094
+            return false;
1095
+        }
1096
+
1097
+        return true;
1098
+    }
1099
+
1100
+    /**
1101
+     * get the installed version of all apps
1102
+     */
1103
+    public static function getAppVersions() {
1104
+        static $versions;
1105
+
1106
+        if(!$versions) {
1107
+            $appConfig = \OC::$server->getAppConfig();
1108
+            $versions = $appConfig->getValues(false, 'installed_version');
1109
+        }
1110
+        return $versions;
1111
+    }
1112
+
1113
+    /**
1114
+     * @param string $app
1115
+     * @return bool
1116
+     * @throws Exception if app is not compatible with this version of ownCloud
1117
+     * @throws Exception if no app-name was specified
1118
+     */
1119
+    public static function installApp($app) {
1120
+        $appName = $app; // $app will be overwritten, preserve name for error logging
1121
+        $l = \OC::$server->getL10N('core');
1122
+        $config = \OC::$server->getConfig();
1123
+        $ocsClient = new OCSClient(
1124
+            \OC::$server->getHTTPClientService(),
1125
+            $config,
1126
+            \OC::$server->getLogger()
1127
+        );
1128
+        $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
1129
+
1130
+        // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
1131
+        if (!is_numeric($app)) {
1132
+            $shippedVersion = self::getAppVersion($app);
1133
+            if ($appData && version_compare($shippedVersion, $appData['version'], '<')) {
1134
+                $app = self::downloadApp($app);
1135
+            } else {
1136
+                $app = Installer::installShippedApp($app);
1137
+            }
1138
+        } else {
1139
+            // Maybe the app is already installed - compare the version in this
1140
+            // case and use the local already installed one.
1141
+            // FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1142
+            $internalAppId = self::getInternalAppIdByOcs($app);
1143
+            if($internalAppId !== false) {
1144
+                if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1145
+                    $app = self::downloadApp($app);
1146
+                } else {
1147
+                    self::enable($internalAppId);
1148
+                    $app = $internalAppId;
1149
+                }
1150
+            } else {
1151
+                $app = self::downloadApp($app);
1152
+            }
1153
+        }
1154
+
1155
+        if ($app !== false) {
1156
+            // check if the app is compatible with this version of ownCloud
1157
+            $info = self::getAppInfo($app);
1158
+            if(!is_array($info)) {
1159
+                throw new \Exception(
1160
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1161
+                        [$info['name']]
1162
+                    )
1163
+                );
1164
+            }
1165
+
1166
+            $version = \OCP\Util::getVersion();
1167
+            if (!self::isAppCompatible($version, $info)) {
1168
+                throw new \Exception(
1169
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1170
+                        array($info['name'])
1171
+                    )
1172
+                );
1173
+            }
1174
+
1175
+            // check for required dependencies
1176
+            $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1177
+            $missing = $dependencyAnalyzer->analyze($info);
1178
+            if (!empty($missing)) {
1179
+                $missingMsg = join(PHP_EOL, $missing);
1180
+                throw new \Exception(
1181
+                    $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1182
+                        array($info['name'], $missingMsg)
1183
+                    )
1184
+                );
1185
+            }
1186
+
1187
+            $config->setAppValue($app, 'enabled', 'yes');
1188
+            if (isset($appData['id'])) {
1189
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1190
+            }
1191
+
1192
+            if(isset($info['settings']) && is_array($info['settings'])) {
1193
+                $appPath = self::getAppPath($app);
1194
+                self::registerAutoloading($app, $appPath);
1195
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1196
+            }
1197
+
1198
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1199
+        } else {
1200
+            if(empty($appName) ) {
1201
+                throw new \Exception($l->t("No app name specified"));
1202
+            } else {
1203
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1204
+            }
1205
+        }
1206
+
1207
+        return $app;
1208
+    }
1209
+
1210
+    /**
1211
+     * update the database for the app and call the update script
1212
+     *
1213
+     * @param string $appId
1214
+     * @return bool
1215
+     */
1216
+    public static function updateApp($appId) {
1217
+        $appPath = self::getAppPath($appId);
1218
+        if($appPath === false) {
1219
+            return false;
1220
+        }
1221
+        $appData = self::getAppInfo($appId);
1222
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1223
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1224
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1225
+        }
1226
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1227
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1228
+        unset(self::$appVersion[$appId]);
1229
+        // run upgrade code
1230
+        if (file_exists($appPath . '/appinfo/update.php')) {
1231
+            self::loadApp($appId, false);
1232
+            include $appPath . '/appinfo/update.php';
1233
+        }
1234
+        self::setupBackgroundJobs($appData['background-jobs']);
1235
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1236
+            $appPath = self::getAppPath($appId);
1237
+            self::registerAutoloading($appId, $appPath);
1238
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1239
+        }
1240
+
1241
+        //set remote/public handlers
1242
+        if (array_key_exists('ocsid', $appData)) {
1243
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1244
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1245
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1246
+        }
1247
+        foreach ($appData['remote'] as $name => $path) {
1248
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1249
+        }
1250
+        foreach ($appData['public'] as $name => $path) {
1251
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1252
+        }
1253
+
1254
+        self::setAppTypes($appId);
1255
+
1256
+        $version = \OC_App::getAppVersion($appId);
1257
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1258
+
1259
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1260
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1261
+        ));
1262
+
1263
+        return true;
1264
+    }
1265
+
1266
+    /**
1267
+     * @param string $appId
1268
+     * @param string[] $steps
1269
+     * @throws \OC\NeedsUpdateException
1270
+     */
1271
+    public static function executeRepairSteps($appId, array $steps) {
1272
+        if (empty($steps)) {
1273
+            return;
1274
+        }
1275
+        // load the app
1276
+        self::loadApp($appId, false);
1277
+
1278
+        $dispatcher = OC::$server->getEventDispatcher();
1279
+
1280
+        // load the steps
1281
+        $r = new Repair([], $dispatcher);
1282
+        foreach ($steps as $step) {
1283
+            try {
1284
+                $r->addStep($step);
1285
+            } catch (Exception $ex) {
1286
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1287
+                \OC::$server->getLogger()->logException($ex);
1288
+            }
1289
+        }
1290
+        // run the steps
1291
+        $r->run();
1292
+    }
1293
+
1294
+    public static function setupBackgroundJobs(array $jobs) {
1295
+        $queue = \OC::$server->getJobList();
1296
+        foreach ($jobs as $job) {
1297
+            $queue->add($job);
1298
+        }
1299
+    }
1300
+
1301
+    /**
1302
+     * @param string $appId
1303
+     * @param string[] $steps
1304
+     */
1305
+    private static function setupLiveMigrations($appId, array $steps) {
1306
+        $queue = \OC::$server->getJobList();
1307
+        foreach ($steps as $step) {
1308
+            $queue->add('OC\Migration\BackgroundRepair', [
1309
+                'app' => $appId,
1310
+                'step' => $step]);
1311
+        }
1312
+    }
1313
+
1314
+    /**
1315
+     * @param string $appId
1316
+     * @return \OC\Files\View|false
1317
+     */
1318
+    public static function getStorage($appId) {
1319
+        if (OC_App::isEnabled($appId)) { //sanity check
1320
+            if (OC_User::isLoggedIn()) {
1321
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1322
+                if (!$view->file_exists($appId)) {
1323
+                    $view->mkdir($appId);
1324
+                }
1325
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1326
+            } else {
1327
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1328
+                return false;
1329
+            }
1330
+        } else {
1331
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1332
+            return false;
1333
+        }
1334
+    }
1335
+
1336
+    protected static function findBestL10NOption($options, $lang) {
1337
+        $fallback = $similarLangFallback = $englishFallback = false;
1338
+
1339
+        $lang = strtolower($lang);
1340
+        $similarLang = $lang;
1341
+        if (strpos($similarLang, '_')) {
1342
+            // For "de_DE" we want to find "de" and the other way around
1343
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1344
+        }
1345
+
1346
+        foreach ($options as $option) {
1347
+            if (is_array($option)) {
1348
+                if ($fallback === false) {
1349
+                    $fallback = $option['@value'];
1350
+                }
1351
+
1352
+                if (!isset($option['@attributes']['lang'])) {
1353
+                    continue;
1354
+                }
1355
+
1356
+                $attributeLang = strtolower($option['@attributes']['lang']);
1357
+                if ($attributeLang === $lang) {
1358
+                    return $option['@value'];
1359
+                }
1360
+
1361
+                if ($attributeLang === $similarLang) {
1362
+                    $similarLangFallback = $option['@value'];
1363
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1364
+                    if ($similarLangFallback === false) {
1365
+                        $similarLangFallback =  $option['@value'];
1366
+                    }
1367
+                }
1368
+            } else {
1369
+                $englishFallback = $option;
1370
+            }
1371
+        }
1372
+
1373
+        if ($similarLangFallback !== false) {
1374
+            return $similarLangFallback;
1375
+        } else if ($englishFallback !== false) {
1376
+            return $englishFallback;
1377
+        }
1378
+        return (string) $fallback;
1379
+    }
1380
+
1381
+    /**
1382
+     * parses the app data array and enhanced the 'description' value
1383
+     *
1384
+     * @param array $data the app data
1385
+     * @param string $lang
1386
+     * @return array improved app data
1387
+     */
1388
+    public static function parseAppInfo(array $data, $lang = null) {
1389
+
1390
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1391
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1392
+        }
1393
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1394
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1395
+        }
1396
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1397
+            $data['description'] = self::findBestL10NOption($data['description'], $lang);
1398
+        }
1399
+
1400
+        // just modify the description if it is available
1401
+        // otherwise this will create a $data element with an empty 'description'
1402
+        if (isset($data['description'])) {
1403
+            if (is_string($data['description'])) {
1404
+                // sometimes the description contains line breaks and they are then also
1405
+                // shown in this way in the app management which isn't wanted as HTML
1406
+                // manages line breaks itself
1407
+
1408
+                // first of all we split on empty lines
1409
+                $paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']);
1410
+
1411
+                $result = [];
1412
+                foreach ($paragraphs as $value) {
1413
+                    // replace multiple whitespace (tabs, space, newlines) inside a paragraph
1414
+                    // with a single space - also trims whitespace
1415
+                    $result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value));
1416
+                }
1417
+
1418
+                // join the single paragraphs with a empty line in between
1419
+                $data['description'] = implode("\n\n", $result);
1420
+
1421
+            } else {
1422
+                $data['description'] = '';
1423
+            }
1424
+        }
1425
+
1426
+        return $data;
1427
+    }
1428 1428
 }
Please login to merge, or discard this patch.
Spacing   +61 added lines, -61 removed lines patch added patch discarded remove patch
@@ -109,9 +109,9 @@  discard block
 block discarded – undo
109 109
 		$apps = self::getEnabledApps();
110 110
 
111 111
 		// Add each apps' folder as allowed class path
112
-		foreach($apps as $app) {
112
+		foreach ($apps as $app) {
113 113
 			$path = self::getAppPath($app);
114
-			if($path !== false) {
114
+			if ($path !== false) {
115 115
 				self::registerAutoloading($app, $path);
116 116
 			}
117 117
 		}
@@ -138,15 +138,15 @@  discard block
 block discarded – undo
138 138
 	public static function loadApp($app, $checkUpgrade = true) {
139 139
 		self::$loadedApps[] = $app;
140 140
 		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
141
+		if ($appPath === false) {
142 142
 			return;
143 143
 		}
144 144
 
145 145
 		// in case someone calls loadApp() directly
146 146
 		self::registerAutoloading($app, $appPath);
147 147
 
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
148
+		if (is_file($appPath.'/appinfo/app.php')) {
149
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
150 150
 			if ($checkUpgrade and self::shouldUpgrade($app)) {
151 151
 				throw new \OC\NeedsUpdateException();
152 152
 			}
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
 				// enabled for groups
159 159
 				self::$enabledAppsCache = array();
160 160
 			}
161
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
161
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
162 162
 		}
163 163
 	}
164 164
 
@@ -168,16 +168,16 @@  discard block
 block discarded – undo
168 168
 	 * @param string $path
169 169
 	 */
170 170
 	public static function registerAutoloading($app, $path) {
171
-		$key = $app . '-' . $path;
172
-		if(isset(self::$alreadyRegistered[$key])) {
171
+		$key = $app.'-'.$path;
172
+		if (isset(self::$alreadyRegistered[$key])) {
173 173
 			return;
174 174
 		}
175 175
 		self::$alreadyRegistered[$key] = true;
176 176
 		// Register on PSR-4 composer autoloader
177 177
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
178
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
178
+		\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
179 179
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
180
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
180
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
181 181
 		}
182 182
 
183 183
 		// Register on legacy autoloader
@@ -192,7 +192,7 @@  discard block
 block discarded – undo
192 192
 	private static function requireAppFile($app) {
193 193
 		try {
194 194
 			// encapsulated here to avoid variable scope conflicts
195
-			require_once $app . '/appinfo/app.php';
195
+			require_once $app.'/appinfo/app.php';
196 196
 		} catch (Error $ex) {
197 197
 			\OC::$server->getLogger()->logException($ex);
198 198
 			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
 	 */
247 247
 	public static function setAppTypes($app) {
248 248
 		$appData = self::getAppInfo($app);
249
-		if(!is_array($appData)) {
249
+		if (!is_array($appData)) {
250 250
 			return;
251 251
 		}
252 252
 
@@ -302,8 +302,8 @@  discard block
 block discarded – undo
302 302
 		} else {
303 303
 			$apps = $appManager->getEnabledAppsForUser($user);
304 304
 		}
305
-		$apps = array_filter($apps, function ($app) {
306
-			return $app !== 'files';//we add this manually
305
+		$apps = array_filter($apps, function($app) {
306
+			return $app !== 'files'; //we add this manually
307 307
 		});
308 308
 		sort($apps);
309 309
 		array_unshift($apps, 'files');
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
 		}
355 355
 
356 356
 		$info = self::getAppInfo($app);
357
-		if(isset($info['settings']) && is_array($info['settings'])) {
357
+		if (isset($info['settings']) && is_array($info['settings'])) {
358 358
 			$appPath = self::getAppPath($app);
359 359
 			self::registerAutoloading($app, $appPath);
360 360
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
 		);
374 374
 		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
375 375
 		$download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
376
-		if(isset($download['downloadlink']) and $download['downloadlink']!='') {
376
+		if (isset($download['downloadlink']) and $download['downloadlink'] != '') {
377 377
 			// Replace spaces in download link without encoding entire URL
378 378
 			$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
379 379
 			$info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
 	 */
403 403
 	public static function disable($app) {
404 404
 		// Convert OCS ID to regular application identifier
405
-		if(self::getInternalAppIdByOcs($app) !== false) {
405
+		if (self::getInternalAppIdByOcs($app) !== false) {
406 406
 			$app = self::getInternalAppIdByOcs($app);
407 407
 		}
408 408
 
@@ -465,7 +465,7 @@  discard block
 block discarded – undo
465 465
 			//SubAdmins are also allowed to access user management
466 466
 			$userObject = \OC::$server->getUserSession()->getUser();
467 467
 			$isSubAdmin = false;
468
-			if($userObject !== null) {
468
+			if ($userObject !== null) {
469 469
 				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
470 470
 			}
471 471
 			if ($isSubAdmin) {
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
 	 */
551 551
 	protected static function findAppInDirectories($appId) {
552 552
 		$sanitizedAppId = self::cleanAppId($appId);
553
-		if($sanitizedAppId !== $appId) {
553
+		if ($sanitizedAppId !== $appId) {
554 554
 			return false;
555 555
 		}
556 556
 		static $app_dir = array();
@@ -561,7 +561,7 @@  discard block
 block discarded – undo
561 561
 
562 562
 		$possibleApps = array();
563 563
 		foreach (OC::$APPSROOTS as $dir) {
564
-			if (file_exists($dir['path'] . '/' . $appId)) {
564
+			if (file_exists($dir['path'].'/'.$appId)) {
565 565
 				$possibleApps[] = $dir;
566 566
 			}
567 567
 		}
@@ -602,7 +602,7 @@  discard block
 block discarded – undo
602 602
 		}
603 603
 
604 604
 		if (($dir = self::findAppInDirectories($appId)) != false) {
605
-			return $dir['path'] . '/' . $appId;
605
+			return $dir['path'].'/'.$appId;
606 606
 		}
607 607
 		return false;
608 608
 	}
@@ -628,7 +628,7 @@  discard block
 block discarded – undo
628 628
 	 */
629 629
 	public static function getAppWebPath($appId) {
630 630
 		if (($dir = self::findAppInDirectories($appId)) != false) {
631
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
631
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
632 632
 		}
633 633
 		return false;
634 634
 	}
@@ -654,7 +654,7 @@  discard block
 block discarded – undo
654 654
 	 * @return string
655 655
 	 */
656 656
 	public static function getAppVersionByPath($path) {
657
-		$infoFile = $path . '/appinfo/info.xml';
657
+		$infoFile = $path.'/appinfo/info.xml';
658 658
 		$appData = self::getAppInfo($infoFile, true);
659 659
 		return isset($appData['version']) ? $appData['version'] : '';
660 660
 	}
@@ -677,10 +677,10 @@  discard block
 block discarded – undo
677 677
 				return self::$appInfo[$appId];
678 678
 			}
679 679
 			$appPath = self::getAppPath($appId);
680
-			if($appPath === false) {
680
+			if ($appPath === false) {
681 681
 				return null;
682 682
 			}
683
-			$file = $appPath . '/appinfo/info.xml';
683
+			$file = $appPath.'/appinfo/info.xml';
684 684
 		}
685 685
 
686 686
 		$parser = new \OC\App\InfoParser(\OC::$server->getURLGenerator());
@@ -689,9 +689,9 @@  discard block
 block discarded – undo
689 689
 		if (is_array($data)) {
690 690
 			$data = OC_App::parseAppInfo($data, $lang);
691 691
 		}
692
-		if(isset($data['ocsid'])) {
692
+		if (isset($data['ocsid'])) {
693 693
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
694
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
694
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
695 695
 				$data['ocsid'] = $storedId;
696 696
 			}
697 697
 		}
@@ -771,7 +771,7 @@  discard block
 block discarded – undo
771 771
 	 * @param string $page
772 772
 	 */
773 773
 	public static function registerAdmin($app, $page) {
774
-		self::$adminForms[] = $app . '/' . $page . '.php';
774
+		self::$adminForms[] = $app.'/'.$page.'.php';
775 775
 	}
776 776
 
777 777
 	/**
@@ -780,7 +780,7 @@  discard block
 block discarded – undo
780 780
 	 * @param string $page
781 781
 	 */
782 782
 	public static function registerPersonal($app, $page) {
783
-		self::$personalForms[] = $app . '/' . $page . '.php';
783
+		self::$personalForms[] = $app.'/'.$page.'.php';
784 784
 	}
785 785
 
786 786
 	/**
@@ -809,7 +809,7 @@  discard block
 block discarded – undo
809 809
 
810 810
 		foreach (OC::$APPSROOTS as $apps_dir) {
811 811
 			if (!is_readable($apps_dir['path'])) {
812
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
812
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
813 813
 				continue;
814 814
 			}
815 815
 			$dh = opendir($apps_dir['path']);
@@ -817,7 +817,7 @@  discard block
 block discarded – undo
817 817
 			if (is_resource($dh)) {
818 818
 				while (($file = readdir($dh)) !== false) {
819 819
 
820
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
820
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
821 821
 
822 822
 						$apps[] = $file;
823 823
 					}
@@ -855,12 +855,12 @@  discard block
 block discarded – undo
855 855
 
856 856
 				$info = OC_App::getAppInfo($app, false, $langCode);
857 857
 				if (!is_array($info)) {
858
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
858
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
859 859
 					continue;
860 860
 				}
861 861
 
862 862
 				if (!isset($info['name'])) {
863
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
863
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
864 864
 					continue;
865 865
 				}
866 866
 
@@ -889,13 +889,13 @@  discard block
 block discarded – undo
889 889
 				$info['update'] = ($includeUpdateInfo) ? Installer::isUpdateAvailable($app) : null;
890 890
 
891 891
 				$appPath = self::getAppPath($app);
892
-				if($appPath !== false) {
893
-					$appIcon = $appPath . '/img/' . $app . '.svg';
892
+				if ($appPath !== false) {
893
+					$appIcon = $appPath.'/img/'.$app.'.svg';
894 894
 					if (file_exists($appIcon)) {
895
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
895
+						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app.'.svg');
896 896
 						$info['previewAsIcon'] = true;
897 897
 					} else {
898
-						$appIcon = $appPath . '/img/app.svg';
898
+						$appIcon = $appPath.'/img/app.svg';
899 899
 						if (file_exists($appIcon)) {
900 900
 							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
901 901
 							$info['previewAsIcon'] = true;
@@ -937,9 +937,9 @@  discard block
 block discarded – undo
937 937
 	 * @return string|false
938 938
 	 */
939 939
 	public static function getInternalAppIdByOcs($ocsID) {
940
-		if(is_numeric($ocsID)) {
940
+		if (is_numeric($ocsID)) {
941 941
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
942
-			if(array_search($ocsID, $idArray)) {
942
+			if (array_search($ocsID, $idArray)) {
943 943
 				return array_search($ocsID, $idArray);
944 944
 			}
945 945
 		}
@@ -989,7 +989,7 @@  discard block
 block discarded – undo
989 989
 			$apps[$i]['score'] = $app['score'];
990 990
 			$apps[$i]['removable'] = false;
991 991
 			if ($app['label'] == 'recommended') {
992
-				$apps[$i]['internallabel'] = (string)$l->t('Recommended');
992
+				$apps[$i]['internallabel'] = (string) $l->t('Recommended');
993 993
 				$apps[$i]['internalclass'] = 'recommendedapp';
994 994
 			}
995 995
 
@@ -1103,7 +1103,7 @@  discard block
 block discarded – undo
1103 1103
 	public static function getAppVersions() {
1104 1104
 		static $versions;
1105 1105
 
1106
-		if(!$versions) {
1106
+		if (!$versions) {
1107 1107
 			$appConfig = \OC::$server->getAppConfig();
1108 1108
 			$versions = $appConfig->getValues(false, 'installed_version');
1109 1109
 		}
@@ -1140,8 +1140,8 @@  discard block
 block discarded – undo
1140 1140
 			// case and use the local already installed one.
1141 1141
 			// FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1142 1142
 			$internalAppId = self::getInternalAppIdByOcs($app);
1143
-			if($internalAppId !== false) {
1144
-				if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1143
+			if ($internalAppId !== false) {
1144
+				if ($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1145 1145
 					$app = self::downloadApp($app);
1146 1146
 				} else {
1147 1147
 					self::enable($internalAppId);
@@ -1155,7 +1155,7 @@  discard block
 block discarded – undo
1155 1155
 		if ($app !== false) {
1156 1156
 			// check if the app is compatible with this version of ownCloud
1157 1157
 			$info = self::getAppInfo($app);
1158
-			if(!is_array($info)) {
1158
+			if (!is_array($info)) {
1159 1159
 				throw new \Exception(
1160 1160
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1161 1161
 						[$info['name']]
@@ -1189,7 +1189,7 @@  discard block
 block discarded – undo
1189 1189
 				$config->setAppValue($app, 'ocsid', $appData['id']);
1190 1190
 			}
1191 1191
 
1192
-			if(isset($info['settings']) && is_array($info['settings'])) {
1192
+			if (isset($info['settings']) && is_array($info['settings'])) {
1193 1193
 				$appPath = self::getAppPath($app);
1194 1194
 				self::registerAutoloading($app, $appPath);
1195 1195
 				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -1197,7 +1197,7 @@  discard block
 block discarded – undo
1197 1197
 
1198 1198
 			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1199 1199
 		} else {
1200
-			if(empty($appName) ) {
1200
+			if (empty($appName)) {
1201 1201
 				throw new \Exception($l->t("No app name specified"));
1202 1202
 			} else {
1203 1203
 				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
@@ -1215,24 +1215,24 @@  discard block
 block discarded – undo
1215 1215
 	 */
1216 1216
 	public static function updateApp($appId) {
1217 1217
 		$appPath = self::getAppPath($appId);
1218
-		if($appPath === false) {
1218
+		if ($appPath === false) {
1219 1219
 			return false;
1220 1220
 		}
1221 1221
 		$appData = self::getAppInfo($appId);
1222 1222
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1223
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1224
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1223
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1224
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1225 1225
 		}
1226 1226
 		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1227 1227
 		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1228 1228
 		unset(self::$appVersion[$appId]);
1229 1229
 		// run upgrade code
1230
-		if (file_exists($appPath . '/appinfo/update.php')) {
1230
+		if (file_exists($appPath.'/appinfo/update.php')) {
1231 1231
 			self::loadApp($appId, false);
1232
-			include $appPath . '/appinfo/update.php';
1232
+			include $appPath.'/appinfo/update.php';
1233 1233
 		}
1234 1234
 		self::setupBackgroundJobs($appData['background-jobs']);
1235
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1235
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
1236 1236
 			$appPath = self::getAppPath($appId);
1237 1237
 			self::registerAutoloading($appId, $appPath);
1238 1238
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
@@ -1241,14 +1241,14 @@  discard block
 block discarded – undo
1241 1241
 		//set remote/public handlers
1242 1242
 		if (array_key_exists('ocsid', $appData)) {
1243 1243
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1244
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1244
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1245 1245
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1246 1246
 		}
1247 1247
 		foreach ($appData['remote'] as $name => $path) {
1248
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1248
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1249 1249
 		}
1250 1250
 		foreach ($appData['public'] as $name => $path) {
1251
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1251
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1252 1252
 		}
1253 1253
 
1254 1254
 		self::setAppTypes($appId);
@@ -1318,17 +1318,17 @@  discard block
 block discarded – undo
1318 1318
 	public static function getStorage($appId) {
1319 1319
 		if (OC_App::isEnabled($appId)) { //sanity check
1320 1320
 			if (OC_User::isLoggedIn()) {
1321
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1321
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1322 1322
 				if (!$view->file_exists($appId)) {
1323 1323
 					$view->mkdir($appId);
1324 1324
 				}
1325
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1325
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1326 1326
 			} else {
1327
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1327
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1328 1328
 				return false;
1329 1329
 			}
1330 1330
 		} else {
1331
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1331
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1332 1332
 			return false;
1333 1333
 		}
1334 1334
 	}
@@ -1360,9 +1360,9 @@  discard block
 block discarded – undo
1360 1360
 
1361 1361
 				if ($attributeLang === $similarLang) {
1362 1362
 					$similarLangFallback = $option['@value'];
1363
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1363
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1364 1364
 					if ($similarLangFallback === false) {
1365
-						$similarLangFallback =  $option['@value'];
1365
+						$similarLangFallback = $option['@value'];
1366 1366
 					}
1367 1367
 				}
1368 1368
 			} else {
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/DavAclPlugin.php 4 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -46,6 +46,9 @@
 block discarded – undo
46 46
 		$this->hideNodesFromListings = true;
47 47
 	}
48 48
 
49
+	/**
50
+	 * @param string $privileges
51
+	 */
49 52
 	function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
50 53
 		$access = parent::checkPrivileges($uri, $privileges, $recursion, false);
51 54
 		if($access === false && $throwExceptions) {
Please login to merge, or discard this patch.
Unused Use Statements   -3 removed lines patch added patch discarded remove patch
@@ -25,14 +25,11 @@
 block discarded – undo
25 25
 
26 26
 use Sabre\CalDAV\Principal\User;
27 27
 use Sabre\DAV\Exception\NotFound;
28
-use Sabre\DAV\IFile;
29 28
 use Sabre\DAV\INode;
30 29
 use \Sabre\DAV\PropFind;
31 30
 use \Sabre\DAV\PropPatch;
32
-use Sabre\DAVACL\Exception\NeedPrivileges;
33 31
 use \Sabre\HTTP\RequestInterface;
34 32
 use \Sabre\HTTP\ResponseInterface;
35
-use Sabre\HTTP\URLUtil;
36 33
 
37 34
 /**
38 35
  * Class DavAclPlugin is a wrapper around \Sabre\DAVACL\Plugin that returns 404
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -50,11 +50,11 @@  discard block
 block discarded – undo
50 50
 
51 51
 	function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
52 52
 		$access = parent::checkPrivileges($uri, $privileges, $recursion, false);
53
-		if($access === false && $throwExceptions) {
53
+		if ($access === false && $throwExceptions) {
54 54
 			/** @var INode $node */
55 55
 			$node = $this->server->tree->getNodeForPath($uri);
56 56
 
57
-			switch(get_class($node)) {
57
+			switch (get_class($node)) {
58 58
 				case 'OCA\DAV\CardDAV\AddressBook':
59 59
 					$type = 'Addressbook';
60 60
 					break;
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
 	public function propFind(PropFind $propFind, INode $node) {
78 78
 		// If the node is neither readable nor writable then fail unless its of
79 79
 		// the standard user-principal
80
-		if(!($node instanceof User)) {
80
+		if (!($node instanceof User)) {
81 81
 			$path = $propFind->getPath();
82 82
 			$readPermissions = $this->checkPrivileges($path, '{DAV:}read', self::R_PARENT, false);
83 83
 			$writePermissions = $this->checkPrivileges($path, '{DAV:}write', self::R_PARENT, false);
Please login to merge, or discard this patch.
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -43,49 +43,49 @@
 block discarded – undo
43 43
  * @package OCA\DAV\Connector\Sabre
44 44
  */
45 45
 class DavAclPlugin extends \Sabre\DAVACL\Plugin {
46
-	public function __construct() {
47
-		$this->hideNodesFromListings = true;
48
-	}
46
+    public function __construct() {
47
+        $this->hideNodesFromListings = true;
48
+    }
49 49
 
50
-	function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
51
-		$access = parent::checkPrivileges($uri, $privileges, $recursion, false);
52
-		if($access === false && $throwExceptions) {
53
-			/** @var INode $node */
54
-			$node = $this->server->tree->getNodeForPath($uri);
50
+    function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
51
+        $access = parent::checkPrivileges($uri, $privileges, $recursion, false);
52
+        if($access === false && $throwExceptions) {
53
+            /** @var INode $node */
54
+            $node = $this->server->tree->getNodeForPath($uri);
55 55
 
56
-			switch(get_class($node)) {
57
-				case 'OCA\DAV\CardDAV\AddressBook':
58
-					$type = 'Addressbook';
59
-					break;
60
-				default:
61
-					$type = 'Node';
62
-					break;
63
-			}
64
-			throw new NotFound(
65
-				sprintf(
66
-					"%s with name '%s' could not be found",
67
-					$type,
68
-					$node->getName()
69
-				)
70
-			);
71
-		}
56
+            switch(get_class($node)) {
57
+                case 'OCA\DAV\CardDAV\AddressBook':
58
+                    $type = 'Addressbook';
59
+                    break;
60
+                default:
61
+                    $type = 'Node';
62
+                    break;
63
+            }
64
+            throw new NotFound(
65
+                sprintf(
66
+                    "%s with name '%s' could not be found",
67
+                    $type,
68
+                    $node->getName()
69
+                )
70
+            );
71
+        }
72 72
 
73
-		return $access;
74
-	}
73
+        return $access;
74
+    }
75 75
 
76
-	public function propFind(PropFind $propFind, INode $node) {
77
-		// If the node is neither readable nor writable then fail unless its of
78
-		// the standard user-principal
79
-		if(!($node instanceof User)) {
80
-			$path = $propFind->getPath();
81
-			$readPermissions = $this->checkPrivileges($path, '{DAV:}read', self::R_PARENT, false);
82
-			$writePermissions = $this->checkPrivileges($path, '{DAV:}write', self::R_PARENT, false);
83
-			if ($readPermissions === false && $writePermissions === false) {
84
-				$this->checkPrivileges($path, '{DAV:}read', self::R_PARENT, true);
85
-				$this->checkPrivileges($path, '{DAV:}write', self::R_PARENT, true);
86
-			}
87
-		}
76
+    public function propFind(PropFind $propFind, INode $node) {
77
+        // If the node is neither readable nor writable then fail unless its of
78
+        // the standard user-principal
79
+        if(!($node instanceof User)) {
80
+            $path = $propFind->getPath();
81
+            $readPermissions = $this->checkPrivileges($path, '{DAV:}read', self::R_PARENT, false);
82
+            $writePermissions = $this->checkPrivileges($path, '{DAV:}write', self::R_PARENT, false);
83
+            if ($readPermissions === false && $writePermissions === false) {
84
+                $this->checkPrivileges($path, '{DAV:}read', self::R_PARENT, true);
85
+                $this->checkPrivileges($path, '{DAV:}write', self::R_PARENT, true);
86
+            }
87
+        }
88 88
 
89
-		return parent::propFind($propFind, $node);
90
-	}
89
+        return parent::propFind($propFind, $node);
90
+    }
91 91
 }
Please login to merge, or discard this patch.
apps/files/templates/admin.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -2,17 +2,17 @@
 block discarded – undo
2 2
 
3 3
 	<div class="section">
4 4
 		<h2><?php p($l->t('File handling')); ?></h2>
5
-		<label for="maxUploadSize"><?php p($l->t( 'Maximum upload size' )); ?> </label>
5
+		<label for="maxUploadSize"><?php p($l->t('Maximum upload size')); ?> </label>
6 6
 		<span id="maxUploadSizeSettingsMsg" class="msg"></span>
7 7
 		<br />
8
-		<input type="text" name='maxUploadSize' id="maxUploadSize" value='<?php p($_['uploadMaxFilesize']) ?>' <?php if(!$_['uploadChangable']) { p('disabled'); } ?> />
9
-		<?php if($_['displayMaxPossibleUploadSize']):?>
8
+		<input type="text" name='maxUploadSize' id="maxUploadSize" value='<?php p($_['uploadMaxFilesize']) ?>' <?php if (!$_['uploadChangable']) { p('disabled'); } ?> />
9
+		<?php if ($_['displayMaxPossibleUploadSize']):?>
10 10
 			(<?php p($l->t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>)
11
-		<?php endif;?>
11
+		<?php endif; ?>
12 12
 		<input type="hidden" value="<?php p($_['requesttoken']); ?>" name="requesttoken" />
13
-		<?php if($_['uploadChangable']): ?>
13
+		<?php if ($_['uploadChangable']): ?>
14 14
 			<input type="submit" id="submitMaxUpload"
15
-				   value="<?php p($l->t( 'Save' )); ?>"/>
15
+				   value="<?php p($l->t('Save')); ?>"/>
16 16
 			<p><em><?php p($l->t('With PHP-FPM it might take 5 minutes for changes to be applied.')); ?></em></p>
17 17
 		<?php else: ?>
18 18
 			<p><em><?php p($l->t('Missing permissions to edit from here.')); ?></em></p>
Please login to merge, or discard this patch.
Braces   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -14,7 +14,10 @@
 block discarded – undo
14 14
 			<input type="submit" id="submitMaxUpload"
15 15
 				   value="<?php p($l->t( 'Save' )); ?>"/>
16 16
 			<p><em><?php p($l->t('With PHP-FPM it might take 5 minutes for changes to be applied.')); ?></em></p>
17
-		<?php else: ?>
18
-			<p><em><?php p($l->t('Missing permissions to edit from here.')); ?></em></p>
17
+		<?php else {
18
+    : ?>
19
+			<p><em><?php p($l->t('Missing permissions to edit from here.'));
20
+}
21
+?></em></p>
19 22
 		<?php endif; ?>
20 23
 	</div>
Please login to merge, or discard this patch.
apps/files/templates/simplelist.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -19,14 +19,14 @@
 block discarded – undo
19 19
 		<tr>
20 20
 			<th id='headerName' class="hidden column-name">
21 21
 				<div id="headerName-container">
22
-					<a class="name sort columntitle" data-sort="name"><span><?php p($l->t( 'Name' )); ?></span><span class="sort-indicator"></span></a>
22
+					<a class="name sort columntitle" data-sort="name"><span><?php p($l->t('Name')); ?></span><span class="sort-indicator"></span></a>
23 23
 				</div>
24 24
 			</th>
25 25
 			<th id="headerSize" class="hidden column-size">
26 26
 				<a class="size sort columntitle" data-sort="size"><span><?php p($l->t('Size')); ?></span><span class="sort-indicator"></span></a>
27 27
 			</th>
28 28
 			<th id="headerDate" class="hidden column-mtime">
29
-				<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Modified' )); ?></span><span class="sort-indicator"></span></a>
29
+				<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t('Modified')); ?></span><span class="sort-indicator"></span></a>
30 30
 					<span class="selectedActions"><a href="" class="delete-selected">
31 31
 						<?php p($l->t('Delete'))?>
32 32
 						<img class="svg" alt="<?php p($l->t('Delete'))?>"
Please login to merge, or discard this patch.
apps/files/templates/appnavigation.php 1 patch
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 		<li data-id="<?php p($item['id']) ?>" class="nav-<?php p($item['id']) ?>">
5 5
 			<a href="<?php p(isset($item['href']) ? $item['href'] : '#') ?>"
6 6
 				class="nav-icon-<?php p($item['icon'] !== '' ? $item['icon'] : $item['id']) ?> svg">
7
-				<?php p($item['name']);?>
7
+				<?php p($item['name']); ?>
8 8
 			</a>
9 9
 		</li>
10 10
 		<?php } ?>
@@ -12,7 +12,7 @@  discard block
 block discarded – undo
12 12
 	<div id="app-settings">
13 13
 		<div id="app-settings-header">
14 14
 			<button class="settings-button" data-apps-slide-toggle="#app-settings-content">
15
-				<?php p($l->t('Settings'));?>
15
+				<?php p($l->t('Settings')); ?>
16 16
 			</button>
17 17
 		</div>
18 18
 		<div id="app-settings-content">
@@ -20,9 +20,9 @@  discard block
 block discarded – undo
20 20
 				<input class="checkbox" id="showhiddenfilesToggle" checked="checked" type="checkbox">
21 21
 				<label for="showhiddenfilesToggle"><?php p($l->t('Show hidden files')); ?></label>
22 22
 			</div>
23
-			<label for="webdavurl"><?php p($l->t('WebDAV'));?></label>
23
+			<label for="webdavurl"><?php p($l->t('WebDAV')); ?></label>
24 24
 			<input id="webdavurl" type="text" readonly="readonly" value="<?php p(\OCP\Util::linkToRemote('webdav')); ?>" />
25
-			<em><?php print_unescaped($l->t('Use this address to <a href="%s" target="_blank" rel="noreferrer">access your Files via WebDAV</a>', array(link_to_docs('user-webdav'))));?></em>
25
+			<em><?php print_unescaped($l->t('Use this address to <a href="%s" target="_blank" rel="noreferrer">access your Files via WebDAV</a>', array(link_to_docs('user-webdav')))); ?></em>
26 26
 		</div>
27 27
 	</div>
28 28
 </div>
Please login to merge, or discard this patch.