Completed
Pull Request — stable9 (#707)
by Joas
21:08 queued 11:56
created

Share20OCS::canAccessShare()   D

Complexity

Conditions 9
Paths 6

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 14
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 28
rs 4.909
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 *
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
namespace OCA\Files_Sharing\API;
24
25
use OCP\Files\NotFoundException;
26
use OCP\IGroupManager;
27
use OCP\IUserManager;
28
use OCP\IRequest;
29
use OCP\IURLGenerator;
30
use OCP\IUser;
31
use OCP\Files\IRootFolder;
32
use OCP\Share;
33
use OCP\Share\IManager;
34
35
use OCP\Share\Exceptions\ShareNotFound;
36
use OCP\Share\Exceptions\GenericShareException;
37
38
class Share20OCS {
39
40
	/** @var IManager */
41
	private $shareManager;
42
	/** @var IGroupManager */
43
	private $groupManager;
44
	/** @var IUserManager */
45
	private $userManager;
46
	/** @var IRequest */
47
	private $request;
48
	/** @var IRootFolder */
49
	private $rootFolder;
50
	/** @var IUrlGenerator */
51
	private $urlGenerator;
52
	/** @var IUser */
53
	private $currentUser;
54
55
	/**
56
	 * Share20OCS constructor.
57
	 *
58
	 * @param IManager $shareManager
59
	 * @param IGroupManager $groupManager
60
	 * @param IUserManager $userManager
61
	 * @param IRequest $request
62
	 * @param IRootFolder $rootFolder
63
	 * @param IURLGenerator $urlGenerator
64
	 * @param IUser $currentUser
65
	 */
66
	public function __construct(
67
			IManager $shareManager,
68
			IGroupManager $groupManager,
69
			IUserManager $userManager,
70
			IRequest $request,
71
			IRootFolder $rootFolder,
72
			IURLGenerator $urlGenerator,
73
			IUser $currentUser
74
	) {
75
		$this->shareManager = $shareManager;
76
		$this->userManager = $userManager;
77
		$this->groupManager = $groupManager;
78
		$this->request = $request;
79
		$this->rootFolder = $rootFolder;
80
		$this->urlGenerator = $urlGenerator;
0 ignored issues
show
Documentation Bug introduced by
It seems like $urlGenerator of type object<OCP\IURLGenerator> is incompatible with the declared type object<OCA\Files_Sharing\API\IUrlGenerator> of property $urlGenerator.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
81
		$this->currentUser = $currentUser;
82
	}
83
84
	/**
85
	 * Convert an IShare to an array for OCS output
86
	 *
87
	 * @param \OCP\Share\IShare $share
88
	 * @return array
89
	 * @throws NotFoundException In case the node can't be resolved.
90
	 */
91
	protected function formatShare(\OCP\Share\IShare $share) {
92
		$sharedBy = $this->userManager->get($share->getSharedBy());
93
		$shareOwner = $this->userManager->get($share->getShareOwner());
94
		$result = [
95
			'id' => $share->getId(),
96
			'share_type' => $share->getShareType(),
97
			'uid_owner' => $share->getSharedBy(),
98
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
99
			'permissions' => $share->getPermissions(),
100
			'stime' => $share->getShareTime()->getTimestamp(),
101
			'parent' => null,
102
			'expiration' => null,
103
			'token' => null,
104
			'uid_file_owner' => $share->getShareOwner(),
105
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
106
		];
107
108
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
109
		$nodes = $userFolder->getById($share->getNodeId());
110
111
		if (empty($nodes)) {
112
			throw new NotFoundException();
113
		}
114
115
		$node = $nodes[0];
116
		$result['path'] = $userFolder->getRelativePath($node->getPath());
117
118
		if ($node instanceOf \OCP\Files\Folder) {
119
			$result['item_type'] = 'folder';
120
		} else {
121
			$result['item_type'] = 'file';
122
		}
123
		$result['mimetype'] = $node->getMimeType();
124
		$result['storage_id'] = $node->getStorage()->getId();
125
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
126
		$result['item_source'] = $node->getId();
127
		$result['file_source'] = $node->getId();
128
		$result['file_parent'] = $node->getParent()->getId();
129
		$result['file_target'] = $share->getTarget();
130
131
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
132
			$sharedWith = $this->userManager->get($share->getSharedWith());
133
			$result['share_with'] = $share->getSharedWith();
134
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
135
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
136
			$result['share_with'] = $share->getSharedWith();
137
			$result['share_with_displayname'] = $share->getSharedWith();
138
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
139
140
			$result['share_with'] = $share->getPassword();
141
			$result['share_with_displayname'] = $share->getPassword();
142
143
			$result['token'] = $share->getToken();
144
			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
145
146
			$expiration = $share->getExpirationDate();
147
			if ($expiration !== null) {
148
				$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
149
			}
150
151
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
152
			$result['share_with'] = $share->getSharedWith();
153
			$result['share_with_displayname'] = $share->getSharedWith();
154
			$result['token'] = $share->getToken();
155
		}
156
157
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
158
159
		return $result;
160
	}
161
162
	/**
163
	 * Get a specific share by id
164
	 *
165
	 * @param string $id
166
	 * @return \OC_OCS_Result
167
	 */
168
	public function getShare($id) {
169
		if (!$this->shareManager->shareApiEnabled()) {
170
			return new \OC_OCS_Result(null, 404, 'Share API is disabled');
171
		}
172
173
		// Try both our default, and our federated provider..
174
		$share = null;
175
176
		// First check if it is an internal share.
177
178
		try {
179
			$share = $this->shareManager->getShareById('ocinternal:'.$id);
180
		} catch (ShareNotFound $e) {
181
			// Ignore for now
182
			//return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
183
		}
184
185 View Code Duplication
		if ($share === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
187
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
188
			}
189
190
			try {
191
				$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
192
			} catch (ShareNotFound $e) {
193
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
194
			}
195
		}
196
197
		if ($this->canAccessShare($share)) {
198
			try {
199
				$share = $this->formatShare($share);
200
				return new \OC_OCS_Result([$share]);
201
			} catch (NotFoundException $e) {
202
				//Fall trough
203
			}
204
		}
205
206
		return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
207
	}
208
209
	/**
210
	 * Delete a share
211
	 *
212
	 * @param string $id
213
	 * @return \OC_OCS_Result
214
	 */
215
	public function deleteShare($id) {
216
		if (!$this->shareManager->shareApiEnabled()) {
217
			return new \OC_OCS_Result(null, 404, 'Share API is disabled');
218
		}
219
220
		// Try both our default and our federated provider
221
		$share = null;
222
223
		try {
224
			$share = $this->shareManager->getShareById('ocinternal:' . $id);
225
		} catch (ShareNotFound $e) {
226
			//Ignore for now
227
			//return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
228
		}
229
230
		// Could not find the share as internal share... maybe it is a federated share
231 View Code Duplication
		if ($share === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
232
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
233
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
234
			}
235
236
			try {
237
				$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
238
			} catch (ShareNotFound $e) {
239
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
240
			}
241
		}
242
243
		if (!$this->canAccessShare($share, false)) {
244
			return new \OC_OCS_Result(null, 404, 'could not delete share');
245
		}
246
247
		$this->shareManager->deleteShare($share);
248
249
		return new \OC_OCS_Result();
250
	}
251
252
	/**
253
	 * @return \OC_OCS_Result
254
	 */
255
	public function createShare() {
256
		$share = $this->shareManager->newShare();
257
258
		if (!$this->shareManager->shareApiEnabled()) {
259
			return new \OC_OCS_Result(null, 404, 'Share API is disabled');
260
		}
261
262
		// Verify path
263
		$path = $this->request->getParam('path', null);
264
		if ($path === null) {
265
			return new \OC_OCS_Result(null, 404, 'please specify a file or folder path');
266
		}
267
268
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
269
		try {
270
			$path = $userFolder->get($path);
271
		} catch (\OCP\Files\NotFoundException $e) {
272
			return new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist');
273
		}
274
275
		$share->setNode($path);
276
277
		// Parse permissions (if available)
278
		$permissions = $this->request->getParam('permissions', null);
279
		if ($permissions === null) {
280
			$permissions = \OCP\Constants::PERMISSION_ALL;
281
		} else {
282
			$permissions = (int)$permissions;
283
		}
284
285
		if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
286
			return new \OC_OCS_Result(null, 404, 'invalid permissions');
287
		}
288
289
		// Shares always require read permissions
290
		$permissions |= \OCP\Constants::PERMISSION_READ;
291
292
		if ($path instanceof \OCP\Files\File) {
293
			// Single file shares should never have delete or create permissions
294
			$permissions &= ~\OCP\Constants::PERMISSION_DELETE;
295
			$permissions &= ~\OCP\Constants::PERMISSION_CREATE;
296
		}
297
298
		/*
299
		 * Hack for https://github.com/owncloud/core/issues/22587
300
		 * We check the permissions via webdav. But the permissions of the mount point
301
		 * do not equal the share permissions. Here we fix that for federated mounts.
302
		 */
303
		if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
304
			$permissions &= ~($permissions & ~$path->getPermissions());
305
		}
306
307
		$shareWith = $this->request->getParam('shareWith', null);
308
		$shareType = (int)$this->request->getParam('shareType', '-1');
309
310
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
311
			// Valid user is required to share
312
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
313
				return new \OC_OCS_Result(null, 404, 'please specify a valid user');
314
			}
315
			$share->setSharedWith($shareWith);
316
			$share->setPermissions($permissions);
317
		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
318
			if (!$this->shareManager->allowGroupSharing()) {
319
				return new \OC_OCS_Result(null, 404, 'group sharing is disabled by the administrator');
320
			}
321
322
			// Valid group is required to share
323
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
324
				return new \OC_OCS_Result(null, 404, 'please specify a valid group');
325
			}
326
			$share->setSharedWith($shareWith);
327
			$share->setPermissions($permissions);
328
		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
329
			//Can we even share links?
330
			if (!$this->shareManager->shareApiAllowLinks()) {
331
				return new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator');
332
			}
333
334
			/*
335
			 * For now we only allow 1 link share.
336
			 * Return the existing link share if this is a duplicate
337
			 */
338
			$existingShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
0 ignored issues
show
Documentation introduced by
$path is of type object<OCP\Files\Node>, but the function expects a object<OCP\Files\File>|o...<OCP\Files\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
339
			if (!empty($existingShares)) {
340
				return new \OC_OCS_Result($this->formatShare($existingShares[0]));
341
			}
342
343
			$publicUpload = $this->request->getParam('publicUpload', null);
344
			if ($publicUpload === 'true') {
345
				// Check if public upload is allowed
346
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
347
					return new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
348
				}
349
350
				// Public upload can only be set for folders
351
				if ($path instanceof \OCP\Files\File) {
352
					return new \OC_OCS_Result(null, 404, 'public upload is only possible for public shared folders');
353
				}
354
355
				$share->setPermissions(
356
					\OCP\Constants::PERMISSION_READ |
357
					\OCP\Constants::PERMISSION_CREATE |
358
					\OCP\Constants::PERMISSION_UPDATE
359
				);
360
			} else {
361
				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
362
			}
363
364
			// Set password
365
			$password = $this->request->getParam('password', '');
366
367
			if ($password !== '') {
368
				$share->setPassword($password);
369
			}
370
371
			//Expire date
372
			$expireDate = $this->request->getParam('expireDate', '');
373
374 View Code Duplication
			if ($expireDate !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
375
				try {
376
					$expireDate = $this->parseDate($expireDate);
377
					$share->setExpirationDate($expireDate);
378
				} catch (\Exception $e) {
379
					return new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.');
380
				}
381
			}
382
383
		} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
384
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
385
				return new \OC_OCS_Result(null, 403, 'Sharing '.$path.' failed, because the backend does not allow shares from type '.$shareType);
386
			}
387
388
			$share->setSharedWith($shareWith);
389
			$share->setPermissions($permissions);
390
		} else {
391
			return new \OC_OCS_Result(null, 400, "unknown share type");
392
		}
393
394
		$share->setShareType($shareType);
395
		$share->setSharedBy($this->currentUser->getUID());
396
397
		try {
398
			$share = $this->shareManager->createShare($share);
399
		} catch (GenericShareException $e) {
400
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
401
			return new \OC_OCS_Result(null, $code, $e->getHint());
402
		}catch (\Exception $e) {
403
			return new \OC_OCS_Result(null, 403, $e->getMessage());
404
		}
405
406
		$share = $this->formatShare($share);
407
		return new \OC_OCS_Result($share);
408
	}
409
410
	/**
411
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
412
	 * @return \OC_OCS_Result
413
	 */
414
	private function getSharedWithMe($node = null) {
415
		$userShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $node defined by parameter $node on line 414 can also be of type object<OCP\Files\File> or object<OCP\Files\Folder>; however, OCP\Share\IManager::getSharedWith() does only seem to accept object<OCP\Share\File>|o...<OCP\Share\Folder>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
416
		$groupShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $node defined by parameter $node on line 414 can also be of type object<OCP\Files\File> or object<OCP\Files\Folder>; however, OCP\Share\IManager::getSharedWith() does only seem to accept object<OCP\Share\File>|o...<OCP\Share\Folder>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
417
418
		$shares = array_merge($userShares, $groupShares);
419
420
		$formatted = [];
421
		foreach ($shares as $share) {
422
			if ($this->canAccessShare($share)) {
423
				try {
424
					$formatted[] = $this->formatShare($share);
425
				} catch (NotFoundException $e) {
426
					// Ignore this share
427
				}
428
			}
429
		}
430
431
		return new \OC_OCS_Result($formatted);
432
	}
433
434
	/**
435
	 * @param \OCP\Files\Folder $folder
436
	 * @return \OC_OCS_Result
437
	 */
438
	private function getSharesInDir($folder) {
439
		if (!($folder instanceof \OCP\Files\Folder)) {
440
			return new \OC_OCS_Result(null, 400, "not a directory");
441
		}
442
443
		$nodes = $folder->getDirectoryListing();
444
		/** @var \OCP\Share\IShare[] $shares */
445
		$shares = [];
446
		foreach ($nodes as $node) {
447
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
0 ignored issues
show
Documentation introduced by
$node is of type object<OCP\Files\Node>, but the function expects a object<OCP\Files\File>|o...<OCP\Files\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
448
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
0 ignored issues
show
Documentation introduced by
$node is of type object<OCP\Files\Node>, but the function expects a object<OCP\Files\File>|o...<OCP\Files\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
449
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
0 ignored issues
show
Documentation introduced by
$node is of type object<OCP\Files\Node>, but the function expects a object<OCP\Files\File>|o...<OCP\Files\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
450
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
451
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
0 ignored issues
show
Documentation introduced by
$node is of type object<OCP\Files\Node>, but the function expects a object<OCP\Files\File>|o...<OCP\Files\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
452
			}
453
		}
454
455
		$formatted = [];
456
		foreach ($shares as $share) {
457
			try {
458
				$formatted[] = $this->formatShare($share);
459
			} catch (NotFoundException $e) {
460
				//Ignore this share
461
			}
462
		}
463
464
		return new \OC_OCS_Result($formatted);
465
	}
466
467
	/**
468
	 * The getShares function.
469
	 *
470
	 * - Get shares by the current user
471
	 * - Get shares by the current user and reshares (?reshares=true)
472
	 * - Get shares with the current user (?shared_with_me=true)
473
	 * - Get shares for a specific path (?path=...)
474
	 * - Get all shares in a folder (?subfiles=true&path=..)
475
	 *
476
	 * @return \OC_OCS_Result
477
	 */
478
	public function getShares() {
479
		if (!$this->shareManager->shareApiEnabled()) {
480
			return new \OC_OCS_Result();
481
		}
482
483
		$sharedWithMe = $this->request->getParam('shared_with_me', null);
484
		$reshares = $this->request->getParam('reshares', null);
485
		$subfiles = $this->request->getParam('subfiles');
486
		$path = $this->request->getParam('path', null);
487
488
		if ($path !== null) {
489
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
490
			try {
491
				$path = $userFolder->get($path);
492
			} catch (\OCP\Files\NotFoundException $e) {
493
				return new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist');
494
			}
495
		}
496
497
		if ($sharedWithMe === 'true') {
498
			return $this->getSharedWithMe($path);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCA\Files_Sharing\API\Sh...0OCS::getSharedWithMe() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
499
		}
500
501
		if ($subfiles === 'true') {
502
			return $this->getSharesInDir($path);
0 ignored issues
show
Documentation introduced by
$path is of type object<OCP\Files\Node>|null, but the function expects a object<OCP\Files\Folder>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
503
		}
504
505
		if ($reshares === 'true') {
506
			$reshares = true;
507
		} else {
508
			$reshares = false;
509
		}
510
511
		// Get all shares
512
		$userShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCP\Share\IManager::getSharesBy() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
513
		$groupShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCP\Share\IManager::getSharesBy() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
514
		$linkShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCP\Share\IManager::getSharesBy() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
515
		$shares = array_merge($userShares, $groupShares, $linkShares);
516
517
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
518
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCP\Share\IManager::getSharesBy() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
519
			$shares = array_merge($shares, $federatedShares);
520
		}
521
522
523
		$formatted = [];
524
		foreach ($shares as $share) {
525
			try {
526
				$formatted[] = $this->formatShare($share);
527
			} catch (NotFoundException $e) {
528
				//Ignore share
529
			}
530
		}
531
532
		return new \OC_OCS_Result($formatted);
533
	}
534
535
	/**
536
	 * @param int $id
537
	 * @return \OC_OCS_Result
538
	 */
539
	public function updateShare($id) {
540
		if (!$this->shareManager->shareApiEnabled()) {
541
			return new \OC_OCS_Result(null, 404, 'Share API is disabled');
542
		}
543
544
		// Try both our default and our federated provider
545
		$share = null;
546
547
		try {
548
			$share = $this->shareManager->getShareById('ocinternal:' . $id);
549
		} catch (ShareNotFound $e) {
550
			//Ignore for now
551
			//return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
552
		}
553
554
		// Could not find the share as internal share... maybe it is a federated share
555 View Code Duplication
		if ($share === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
556
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
557
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
558
			}
559
560
			try {
561
				$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
562
			} catch (ShareNotFound $e) {
563
				return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
564
			}
565
		}
566
567
		if (!$this->canAccessShare($share, false)) {
568
			return new \OC_OCS_Result(null, 404, 'wrong share Id, share doesn\'t exist.');
569
		}
570
571
		$permissions = $this->request->getParam('permissions', null);
572
		$password = $this->request->getParam('password', null);
573
		$publicUpload = $this->request->getParam('publicUpload', null);
574
		$expireDate = $this->request->getParam('expireDate', null);
575
576
		/*
577
		 * expirationdate, password and publicUpload only make sense for link shares
578
		 */
579
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
580
			if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) {
581
				return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
582
			}
583
584
			$newPermissions = null;
585
			if ($publicUpload === 'true') {
586
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE;
587
			} else if ($publicUpload === 'false') {
588
				$newPermissions = \OCP\Constants::PERMISSION_READ;
589
			}
590
591
			if ($permissions !== null) {
592
				$newPermissions = (int)$permissions;
593
			}
594
595
			if ($newPermissions !== null &&
596
				$newPermissions !== \OCP\Constants::PERMISSION_READ &&
597
				$newPermissions !== (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) &&
598
				$newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) {
599
				return new \OC_OCS_Result(null, 400, 'can\'t change permission for public link share');
600
			}
601
602
			if ($newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) {
603
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
604
					return new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
605
				}
606
607
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
608
					return new \OC_OCS_Result(null, 400, "public upload is only possible for public shared folders");
609
				}
610
			}
611
612
			if ($newPermissions !== null) {
613
				$share->setPermissions($newPermissions);
614
			}
615
616
			if ($expireDate === '') {
617
				$share->setExpirationDate(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
618 View Code Duplication
			} else if ($expireDate !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
619
				try {
620
					$expireDate = $this->parseDate($expireDate);
621
				} catch (\Exception $e) {
622
					return new \OC_OCS_Result(null, 400, $e->getMessage());
623
				}
624
				$share->setExpirationDate($expireDate);
625
			}
626
627
			if ($password === '') {
628
				$share->setPassword(null);
629
			} else if ($password !== null) {
630
				$share->setPassword($password);
631
			}
632
633
		} else {
634
			// For other shares only permissions is valid.
635
			if ($permissions === null) {
636
				return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
637
			} else {
638
				$permissions = (int)$permissions;
639
				$share->setPermissions($permissions);
640
			}
641
		}
642
643
		if ($permissions !== null) {
644
			/* Check if this is an incomming share */
645
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
0 ignored issues
show
Documentation introduced by
$share->getNode() is of type object<OCP\Files\Folder>, but the function expects a object<OCP\Share\File>|o...<OCP\Share\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
646
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
0 ignored issues
show
Documentation introduced by
$share->getNode() is of type object<OCP\Files\Folder>, but the function expects a object<OCP\Share\File>|o...<OCP\Share\Folder>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
647
648
			if (!empty($incomingShares)) {
649
				$maxPermissions = 0;
650
				foreach ($incomingShares as $incomingShare) {
651
					$maxPermissions |= $incomingShare->getPermissions();
652
				}
653
654
				if ($share->getPermissions() & ~$maxPermissions) {
655
					return new \OC_OCS_Result(null, 404, 'Cannot increase permissions');
656
				}
657
			}
658
		}
659
660
661
		try {
662
			$share = $this->shareManager->updateShare($share);
663
		} catch (\Exception $e) {
664
			return new \OC_OCS_Result(null, 400, $e->getMessage());
665
		}
666
667
		return new \OC_OCS_Result($this->formatShare($share));
668
	}
669
670
	/**
671
	 * @param \OCP\Share\IShare $share
672
	 * @param bool $checkGroups
673
	 * @return bool
674
	 */
675
	protected function canAccessShare(\OCP\Share\IShare $share, $checkGroups = true) {
676
		// A file with permissions 0 can't be accessed by us. So Don't show it
677
		if ($share->getPermissions() === 0) {
678
			return false;
679
		}
680
681
		// Owner of the file and the sharer of the file can always get share
682
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
683
			$share->getSharedBy() === $this->currentUser->getUID()
684
		) {
685
			return true;
686
		}
687
688
		// If the share is shared with you (or a group you are a member of)
689
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
690
			$share->getSharedWith() === $this->currentUser->getUID()) {
691
			return true;
692
		}
693
694
		if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
695
			$sharedWith = $this->groupManager->get($share->getSharedWith());
696
			if ($sharedWith->inGroup($this->currentUser)) {
697
				return true;
698
			}
699
		}
700
701
		return false;
702
	}
703
704
	/**
705
	 * Make sure that the passed date is valid ISO 8601
706
	 * So YYYY-MM-DD
707
	 * If not throw an exception
708
	 *
709
	 * @param string $expireDate
710
	 *
711
	 * @throws \Exception
712
	 * @return \DateTime
713
	 */
714 View Code Duplication
	private function parseDate($expireDate) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
715
		try {
716
			$date = new \DateTime($expireDate);
717
		} catch (\Exception $e) {
718
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
719
		}
720
721
		if ($date === false) {
722
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
723
		}
724
725
		$date->setTime(0,0,0);
726
727
		return $date;
728
	}
729
}
730