Issues (108)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

environment/environment.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Gallery
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 * @author Authors of \OCA\Files_Sharing\Helper
10
 *
11
 * @copyright Olivier Paroz 2016
12
 * @copyright Authors of \OCA\Files_Sharing\Helper 2014-2016
13
 */
14
15
namespace OCA\Gallery\Environment;
16
17
use OCP\IUserManager;
18
use OCP\Share;
19
use OCP\Share\IShare;
20
use OCP\ILogger;
21
use OCP\Files\IRootFolder;
22
use OCP\Files\Folder;
23
use OCP\Files\Node;
24
use OCP\Files\File;
25
use OCP\Files\NotFoundException;
26
27
/**
28
 * Builds the environment so that the services have access to the files and folders' owner
29
 *
30
 * @package OCA\Gallery\Environment
31
 */
32
class Environment {
33
34
	/**
35
	 * @var string
36
	 */
37
	private $appName;
38
	/**
39
	 * The userId of the logged-in user or the person sharing a folder publicly
40
	 *
41
	 * @var string
42
	 */
43
	private $userId;
44
	/**
45
	 * The userFolder of the logged-in user or the ORIGINAL owner of the files which are shared
46
	 * publicly
47
	 *
48
	 * A share needs to be tracked back to its original owner in order to be able to access the
49
	 * resource
50
	 *
51
	 * @var Folder|null
52
	 */
53
	private $userFolder;
54
	/**
55
	 * @var IUserManager
56
	 */
57
	private $userManager;
58
	/**
59
	 * @var int
60
	 */
61
	private $sharedNodeId;
62
	/**
63
	 * @var File|Folder
64
	 */
65
	private $sharedNode;
66
	/**
67
	 * @var IRootFolder
68
	 */
69
	private $rootFolder;
70
	/**
71
	 * @var ILogger
72
	 */
73
	private $logger;
74
	/**
75
	 * The path to the userFolder for users with accounts: /userId/files
76
	 *
77
	 * For public folders, it's the path from the shared folder to the root folder in the original
78
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
79
	 *
80
	 * @var string
81
	 */
82
	private $fromRootToFolder;
83
	/**
84
	 * The name of the shared folder
85
	 *
86
	 * @var string
87
	 */
88
	private $folderName;
89
	/**
90
	 * @var string|null
91
	 */
92
	private $sharePassword;
93
94
	/***
95
	 * Constructor
96
	 *
97
	 * @param string $appName
98
	 * @param string|null $userId
99
	 * @param Folder|null $userFolder
100
	 * @param IUserManager $userManager
101
	 * @param IRootFolder $rootFolder
102
	 * @param ILogger $logger
103
	 */
104
	public function __construct(
105
		$appName,
106
		$userId,
107
		$userFolder,
108
		IUserManager $userManager,
109
		IRootFolder $rootFolder,
110
		ILogger $logger
111
	) {
112
		$this->appName = $appName;
113
		$this->userId = $userId;
114
		$this->userFolder = $userFolder;
115
		$this->userManager = $userManager;
116
		$this->rootFolder = $rootFolder;
117
		$this->logger = $logger;
118
	}
119
120
	/**
121
	 * Creates the environment based on the share the token links to
122
	 *
123
	 * @param IShare $share
124
	 */
125
	public function setTokenBasedEnv($share) {
126
		$origShareOwnerId = $share->getShareOwner();
127
		$this->userFolder = $this->rootFolder->getUserFolder($origShareOwnerId);
128
129
		$this->sharedNodeId = $share->getNodeId();
130
		$this->sharedNode = $share->getNode();
131
		$this->fromRootToFolder = $this->buildFromRootToFolder($this->sharedNodeId);
132
133
		$this->folderName = $share->getTarget();
134
		$this->userId = $origShareOwnerId;
135
		$this->sharePassword = $share->getPassword();
136
	}
137
138
	/**
139
	 * Creates the environment for a logged-in user
140
	 *
141
	 * userId and userFolder are already known, we define fromRootToFolder
142
	 * so that the services can use one method to have access to resources
143
	 * without having to know whether they're private or public
144
	 */
145
	public function setStandardEnv() {
146
		$this->fromRootToFolder = $this->userFolder->getPath() . '/';
147
	}
148
149
	/**
150
	 * Returns true if the environment has been setup using a token
151
	 *
152
	 * @return bool
153
	 */
154
	public function isTokenBasedEnv() {
155
		return !empty($this->sharedNodeId);
156
	}
157
158
	/**
159
	 * Returns the Node based on a path starting from the virtual root
160
	 *
161
	 * @param string $subPath
162
	 *
163
	 * @return File|Folder
0 ignored issues
show
Should the return type not be Node?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
164
	 */
165
	public function getNodeFromVirtualRoot($subPath) {
166
		$relativePath = $this->getRelativePath($this->fromRootToFolder);
167
		$path = $relativePath . '/' . $subPath;
168
		$node = $this->getNodeFromUserFolder($path);
169
170
		return $this->getResourceFromId($node->getId());
171
	}
172
173
	/**
174
	 * Returns the Node based on a path starting from the files' owner user folder
175
	 *
176
	 * When logged in, this is the current user's user folder
177
	 * When visiting a link, this is the sharer's user folder
178
	 *
179
	 * @param string $path
180
	 *
181
	 * @return File|Folder
182
	 *
183
	 * @throws NotFoundEnvException
184
	 */
185
	public function getNodeFromUserFolder($path) {
186
		$folder = $this->userFolder;
187
		if ($folder === null) {
188
			throw new NotFoundEnvException("Could not access the user's folder");
189
		} else {
190
			try {
191
				$node = $folder->get($path);
192
			} catch (NotFoundException $exception) {
0 ignored issues
show
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
193
				$message = 'Could not find anything at: ' . $exception->getMessage();
194
				throw new NotFoundEnvException($message);
195
			}
196
		}
197
198
		return $node;
199
	}
200
201
	/**
202
	 * Returns the resource identified by the given ID
203
	 *
204
	 * @param int $resourceId
205
	 *
206
	 * @return Node
207
	 *
208
	 * @throws NotFoundEnvException
209
	 */
210
	public function getResourceFromId($resourceId) {
211
		if ($this->isTokenBasedEnv()) {
212
			if ($this->sharedNode->getType() === 'dir') {
213
				$resource = $this->getResourceFromFolderAndId($this->sharedNode, $resourceId);
214
			} else {
215
				$resource = $this->sharedNode;
216
			}
217
		} else {
218
			$resource = $this->getResourceFromFolderAndId($this->userFolder, $resourceId);
0 ignored issues
show
It seems like $this->userFolder can be null; however, getResourceFromFolderAndId() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
219
		}
220
221
		return $resource;
222
	}
223
224
	/**
225
	 * Returns the shared node
226
	 *
227
	 * @return File|Folder
0 ignored issues
show
Should the return type not be Node?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
228
	 */
229
	public function getSharedNode() {
230
		return $this->getResourceFromId($this->sharedNodeId);
231
	}
232
233
	/**
234
	 * Returns the virtual root where the user lands after logging in or when following a link
235
	 *
236
	 * @return Folder
0 ignored issues
show
Should the return type not be Folder|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
237
	 * @throws NotFoundEnvException
238
	 */
239
	public function getVirtualRootFolder() {
240
		$rootFolder = $this->userFolder;
241
		if ($this->isTokenBasedEnv()) {
242
			$node = $this->getSharedNode();
243
			$nodeType = $node->getType();
244
			if ($nodeType === 'dir') {
245
				$rootFolder = $node;
246
			} else {
247
				throw new NotFoundEnvException($node->getPath() . ' is not a folder');
248
			}
249
		}
250
251
		return $rootFolder;
252
	}
253
254
	/**
255
	 * Returns the userId of the currently logged-in user or the sharer
256
	 *
257
	 * @return string
258
	 */
259
	public function getUserId() {
260
		return $this->userId;
261
	}
262
263
	/**
264
	 * Returns the name of the user sharing files publicly
265
	 *
266
	 * @return string
267
	 * @throws NotFoundEnvException
268
	 */
269
	public function getDisplayName() {
270
		$user = null;
271
		$userId = $this->userId;
272
273
		if (isset($userId)) {
274
			$user = $this->userManager->get($userId);
275
		}
276
		if ($user === null) {
277
			throw new NotFoundEnvException('Could not find user');
278
		}
279
280
		return $user->getDisplayName();
281
	}
282
283
	/**
284
	 * Returns the name of shared folder
285
	 *
286
	 * @return string
287
	 */
288
	public function getSharedFolderName() {
289
		return \trim($this->folderName, '//');
290
	}
291
292
	/**
293
	 * Returns the password for the share, if there is one
294
	 *
295
	 * @return string|null
296
	 */
297
	public function getSharePassword() {
298
		return $this->sharePassword;
299
	}
300
301
	/**
302
	 * Returns the path which goes from the file, up to the user folder, based on a node:
303
	 * parent_folder/current_folder/my_file
304
	 *
305
	 * This is used for the preview system, which needs a full path
306
	 *
307
	 * getPath() on the file produces a path like:
308
	 * '/userId/files/my_folder/my_sub_folder/my_file'
309
	 *
310
	 * So we substract the path to the folder, giving us a relative path
311
	 * 'my_folder/my_sub_folder/my_file'
312
	 *
313
	 * @param Node $file
314
	 *
315
	 * @return string
316
	 */
317
	public function getPathFromUserFolder($file) {
318
		$path = $file->getPath();
319
320
		return $this->getRelativePath($path);
321
	}
322
323
	/**
324
	 * Returns the path which goes from the file, up to the root folder of the Gallery:
325
	 * current_folder/my_file
326
	 *
327
	 * That root folder changes when folders are shared publicly
328
	 *
329
	 * @param File|Folder|Node $node
330
	 *
331
	 * @return string
332
	 */
333
	public function getPathFromVirtualRoot($node) {
334
		$path = $node->getPath();
335
		$nodeType = $node->getType();
336
337
		// Needed because fromRootToFolder always ends with a slash
338
		if ($nodeType === 'dir') {
339
			$path .= '/';
340
		}
341
342
		$path = \str_replace($this->fromRootToFolder, '', $path);
343
		$path = \rtrim($path, '/');
344
345
		return $path;
346
	}
347
348
	/**
349
	 * Returns the resource found in a specific folder and identified by the given ID
350
	 *
351
	 * @param Folder $folder
352
	 * @param int $resourceId
353
	 *
354
	 * @return Node
355
	 * @throws NotFoundEnvException
356
	 */
357
	private function getResourceFromFolderAndId($folder, $resourceId) {
358
		$resourcesArray = $folder->getById($resourceId);
359
360
		if ($resourcesArray[0] === null) {
361
			throw new NotFoundEnvException('Could not locate node linked to ID: ' . $resourceId);
362
		}
363
364
		return $resourcesArray[0];
365
	}
366
367
	/**
368
	 * Returns the path from the shared folder to the root folder in the original
369
	 * owner's filesystem: /userId/files/parent_folder/shared_folder
370
	 *
371
	 * This cannot be calculated with paths and IDs, the share's file source is required
372
	 *
373
	 * @param string $fileSource
374
	 *
375
	 * @return string
376
	 */
377
	private function buildFromRootToFolder($fileSource) {
378
		$resource = $this->getResourceFromId($fileSource);
379
		$fromRootToFolder = $resource->getPath() . '/';
380
381
		return $fromRootToFolder;
382
	}
383
384
	/**
385
	 * Returns the path which goes from the file, up to the user folder, based on a path:
386
	 * parent_folder/current_folder/my_file
387
	 *
388
	 * getPath() on the file produces a path like:
389
	 * '/userId/files/my_folder/my_sub_folder/my_file'
390
	 *
391
	 * So we substract the path to the user folder, giving us a relative path
392
	 * 'my_folder/my_sub_folder'
393
	 *
394
	 * @param string $fullPath
395
	 *
396
	 * @return string
397
	 */
398
	private function getRelativePath($fullPath) {
399
		$folderPath = $this->userFolder->getPath() . '/';
400
		$origShareRelPath = \str_replace($folderPath, '', $fullPath);
401
402
		return $origShareRelPath;
403
	}
404
}
405