Passed
Push — master ( 4ebb20...72b7c9 )
by Roeland
12:19
created

ShareAPIController::updateShare()   F

Complexity

Conditions 49
Paths > 20000

Size

Total Lines 192
Code Lines 109

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 49
eloc 109
nc 57907
nop 9
dl 0
loc 192
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Maxence Lange <[email protected]>
10
 * @author Michael Jobst <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
namespace OCA\Files_Sharing\Controller;
31
32
use OCA\Files\Helper;
33
use OCP\App\IAppManager;
34
use OCP\AppFramework\Http\DataResponse;
35
use OCP\AppFramework\OCS\OCSBadRequestException;
36
use OCP\AppFramework\OCS\OCSException;
37
use OCP\AppFramework\OCS\OCSForbiddenException;
38
use OCP\AppFramework\OCS\OCSNotFoundException;
39
use OCP\AppFramework\OCSController;
40
use OCP\AppFramework\QueryException;
41
use OCP\Constants;
42
use OCP\Files\Node;
43
use OCP\Files\NotFoundException;
44
use OCP\IConfig;
45
use OCP\IGroupManager;
46
use OCP\IL10N;
47
use OCP\IUserManager;
48
use OCP\IRequest;
49
use OCP\IServerContainer;
50
use OCP\IURLGenerator;
51
use OCP\Files\IRootFolder;
52
use OCP\Lock\LockedException;
53
use OCP\Share;
54
use OCP\Share\IManager;
55
use OCP\Share\Exceptions\ShareNotFound;
56
use OCP\Share\Exceptions\GenericShareException;
57
use OCP\Lock\ILockingProvider;
58
use OCP\Share\IShare;
59
use OCA\Files_Sharing\External\Storage;
60
61
/**
62
 * Class Share20OCS
63
 *
64
 * @package OCA\Files_Sharing\API
65
 */
66
class ShareAPIController extends OCSController {
67
68
	/** @var IManager */
69
	private $shareManager;
70
	/** @var IGroupManager */
71
	private $groupManager;
72
	/** @var IUserManager */
73
	private $userManager;
74
	/** @var IRootFolder */
75
	private $rootFolder;
76
	/** @var IURLGenerator */
77
	private $urlGenerator;
78
	/** @var string */
79
	private $currentUser;
80
	/** @var IL10N */
81
	private $l;
82
	/** @var \OCP\Files\Node */
83
	private $lockedNode;
84
	/** @var IConfig */
85
	private $config;
86
	/** @var IAppManager */
87
	private $appManager;
88
	/** @var IServerContainer */
89
	private $serverContainer;
90
91
	/**
92
	 * Share20OCS constructor.
93
	 *
94
	 * @param string $appName
95
	 * @param IRequest $request
96
	 * @param IManager $shareManager
97
	 * @param IGroupManager $groupManager
98
	 * @param IUserManager $userManager
99
	 * @param IRootFolder $rootFolder
100
	 * @param IURLGenerator $urlGenerator
101
	 * @param string $userId
102
	 * @param IL10N $l10n
103
	 * @param IConfig $config
104
	 * @param IAppManager $appManager
105
	 * @param IServerContainer $serverContainer
106
	 */
107
	public function __construct(
108
		string $appName,
109
		IRequest $request,
110
		IManager $shareManager,
111
		IGroupManager $groupManager,
112
		IUserManager $userManager,
113
		IRootFolder $rootFolder,
114
		IURLGenerator $urlGenerator,
115
		string $userId = null,
116
		IL10N $l10n,
117
		IConfig $config,
118
		IAppManager $appManager,
119
		IServerContainer $serverContainer
120
	) {
121
		parent::__construct($appName, $request);
122
123
		$this->shareManager = $shareManager;
124
		$this->userManager = $userManager;
125
		$this->groupManager = $groupManager;
126
		$this->request = $request;
127
		$this->rootFolder = $rootFolder;
128
		$this->urlGenerator = $urlGenerator;
129
		$this->currentUser = $userId;
130
		$this->l = $l10n;
131
		$this->config = $config;
132
		$this->appManager = $appManager;
133
		$this->serverContainer = $serverContainer;
134
	}
135
136
	/**
137
	 * Convert an IShare to an array for OCS output
138
	 *
139
	 * @param \OCP\Share\IShare $share
140
	 * @param Node|null $recipientNode
141
	 * @return array
142
	 * @throws NotFoundException In case the node can't be resolved.
143
	 *
144
	 * @suppress PhanUndeclaredClassMethod
145
	 */
146
	protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array {
147
		$sharedBy = $this->userManager->get($share->getSharedBy());
148
		$shareOwner = $this->userManager->get($share->getShareOwner());
149
150
		$result = [
151
			'id' => $share->getId(),
152
			'share_type' => $share->getShareType(),
153
			'uid_owner' => $share->getSharedBy(),
154
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
155
			'permissions' => $share->getPermissions(),
156
			'stime' => $share->getShareTime()->getTimestamp(),
157
			'parent' => null,
158
			'expiration' => null,
159
			'token' => null,
160
			'uid_file_owner' => $share->getShareOwner(),
161
			'note' => $share->getNote(),
162
			'label' => $share->getLabel(),
163
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
164
		];
165
166
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
167
		if ($recipientNode) {
168
			$node = $recipientNode;
169
		} else {
170
			$nodes = $userFolder->getById($share->getNodeId());
171
			if (empty($nodes)) {
172
				// fallback to guessing the path
173
				$node = $userFolder->get($share->getTarget());
174
				if ($node === null || $share->getTarget() === '') {
175
					throw new NotFoundException();
176
				}
177
			} else {
178
				$node = $nodes[0];
179
			}
180
		}
181
182
		$result['path'] = $userFolder->getRelativePath($node->getPath());
183
		if ($node instanceOf \OCP\Files\Folder) {
184
			$result['item_type'] = 'folder';
185
		} else {
186
			$result['item_type'] = 'file';
187
		}
188
		$result['mimetype'] = $node->getMimetype();
189
		$result['storage_id'] = $node->getStorage()->getId();
190
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
191
		$result['item_source'] = $node->getId();
192
		$result['file_source'] = $node->getId();
193
		$result['file_parent'] = $node->getParent()->getId();
194
		$result['file_target'] = $share->getTarget();
195
196
		$expiration = $share->getExpirationDate();
197
		if ($expiration !== null) {
198
			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
199
		}
200
201
		if ($share->getShareType() === Share::SHARE_TYPE_USER) {
202
			$sharedWith = $this->userManager->get($share->getSharedWith());
203
			$result['share_with'] = $share->getSharedWith();
204
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
205
		} else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
206
			$group = $this->groupManager->get($share->getSharedWith());
207
			$result['share_with'] = $share->getSharedWith();
208
			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
209
		} else if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
210
211
			$result['share_with'] = $share->getPassword();
212
			$result['share_with_displayname'] = $share->getPassword();
213
214
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
215
216
			$result['token'] = $share->getToken();
217
			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
218
219
		} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {
220
			$result['share_with'] = $share->getSharedWith();
221
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
222
			$result['token'] = $share->getToken();
223
		} else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
224
			$result['share_with'] = $share->getSharedWith();
225
			$result['password'] = $share->getPassword();
226
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
227
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
228
			$result['token'] = $share->getToken();
229
		} else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
230
			// getSharedWith() returns either "name (type, owner)" or
231
			// "name (type, owner) [id]", depending on the Circles app version.
232
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
233
234
			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
235
			if (empty($result['share_with_displayname'])) {
236
				$displayNameLength = ($hasCircleId? strrpos($share->getSharedWith(), ' '): strlen($share->getSharedWith()));
237
				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
238
			}
239
240
			$result['share_with_avatar'] = $share->getSharedWithAvatar();
241
242
			$shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0);
243
			$shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' '));
244
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
245
				$shareWithLength = -1;
246
			}
247
			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
248
		} else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
249
			$result['share_with'] = $share->getSharedWith();
250
			$result['share_with_displayname'] = '';
251
252
			try {
253
				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
254
			} catch (QueryException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
255
			}
256
		}
257
258
259
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
260
		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
261
262
		return $result;
263
	}
264
265
	/**
266
	 * Check if one of the users address books knows the exact property, if
267
	 * yes we return the full name.
268
	 *
269
	 * @param string $query
270
	 * @param string $property
271
	 * @return string
272
	 */
273
	private function getDisplayNameFromAddressBook(string $query, string $property): string {
274
		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
275
		$result = \OC::$server->getContactsManager()->search($query, [$property]);
276
		foreach ($result as $r) {
277
			foreach($r[$property] as $value) {
278
				if ($value === $query) {
279
					return $r['FN'];
280
				}
281
			}
282
		}
283
284
		return $query;
285
	}
286
287
	/**
288
	 * Get a specific share by id
289
	 *
290
	 * @NoAdminRequired
291
	 *
292
	 * @param string $id
293
	 * @return DataResponse
294
	 * @throws OCSNotFoundException
295
	 */
296
	public function getShare(string $id): DataResponse {
297
		try {
298
			$share = $this->getShareById($id);
299
		} catch (ShareNotFound $e) {
300
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
301
		}
302
303
		if ($this->canAccessShare($share)) {
304
			try {
305
				$share = $this->formatShare($share);
306
				return new DataResponse([$share]);
307
			} catch (NotFoundException $e) {
308
				//Fall trough
309
			}
310
		}
311
312
		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
313
	}
314
315
	/**
316
	 * Delete a share
317
	 *
318
	 * @NoAdminRequired
319
	 *
320
	 * @param string $id
321
	 * @return DataResponse
322
	 * @throws OCSNotFoundException
323
	 */
324
	public function deleteShare(string $id): DataResponse {
325
		try {
326
			$share = $this->getShareById($id);
327
		} catch (ShareNotFound $e) {
328
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
329
		}
330
331
		try {
332
			$this->lock($share->getNode());
333
		} catch (LockedException $e) {
334
			throw new OCSNotFoundException($this->l->t('could not delete share'));
335
		}
336
337
		if (!$this->canAccessShare($share)) {
338
			throw new OCSNotFoundException($this->l->t('Could not delete share'));
339
		}
340
341
		if (($share->getShareType() === Share::SHARE_TYPE_GROUP ||
342
				$share->getShareType() === Share::SHARE_TYPE_ROOM) &&
343
			$share->getShareOwner() !== $this->currentUser &&
344
			$share->getSharedBy() !== $this->currentUser) {
345
			$this->shareManager->deleteFromSelf($share, $this->currentUser);
346
		} else {
347
			$this->shareManager->deleteShare($share);
348
		}
349
350
		return new DataResponse();
351
	}
352
353
	/**
354
	 * @NoAdminRequired
355
	 *
356
	 * @param string $path
357
	 * @param int $permissions
358
	 * @param int $shareType
359
	 * @param string $shareWith
360
	 * @param string $publicUpload
361
	 * @param string $password
362
	 * @param string $sendPasswordByTalk
363
	 * @param string $expireDate
364
	 * @param string $label
365
	 *
366
	 * @return DataResponse
367
	 * @throws NotFoundException
368
	 * @throws OCSBadRequestException
369
	 * @throws OCSException
370
	 * @throws OCSForbiddenException
371
	 * @throws OCSNotFoundException
372
	 * @throws \OCP\Files\InvalidPathException
373
	 * @suppress PhanUndeclaredClassMethod
374
	 */
375
	public function createShare(
376
		string $path = null,
377
		int $permissions = null,
378
		int $shareType = -1,
379
		string $shareWith = null,
380
		string $publicUpload = 'false',
381
		string $password = '',
382
		string $sendPasswordByTalk = null,
383
		string $expireDate = '',
384
		string $label = ''
385
	): DataResponse {
386
		$share = $this->shareManager->newShare();
387
388
		if ($permissions === null) {
389
			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
390
		}
391
392
		// Verify path
393
		if ($path === null) {
394
			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
395
		}
396
397
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
398
		try {
399
			$path = $userFolder->get($path);
400
		} catch (NotFoundException $e) {
401
			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
402
		}
403
404
		$share->setNode($path);
405
406
		try {
407
			$this->lock($share->getNode());
408
		} catch (LockedException $e) {
409
			throw new OCSNotFoundException($this->l->t('Could not create share'));
410
		}
411
412
		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
413
			throw new OCSNotFoundException($this->l->t('invalid permissions'));
414
		}
415
416
		// Shares always require read permissions
417
		$permissions |= Constants::PERMISSION_READ;
418
419
		if ($path instanceof \OCP\Files\File) {
420
			// Single file shares should never have delete or create permissions
421
			$permissions &= ~Constants::PERMISSION_DELETE;
422
			$permissions &= ~Constants::PERMISSION_CREATE;
423
		}
424
425
		/*
426
		 * Hack for https://github.com/owncloud/core/issues/22587
427
		 * We check the permissions via webdav. But the permissions of the mount point
428
		 * do not equal the share permissions. Here we fix that for federated mounts.
429
		 */
430
		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
431
			$permissions &= ~($permissions & ~$path->getPermissions());
432
		}
433
434
		if ($shareType === Share::SHARE_TYPE_USER) {
435
			// Valid user is required to share
436
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
437
				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
438
			}
439
			$share->setSharedWith($shareWith);
440
			$share->setPermissions($permissions);
441
		} else if ($shareType === Share::SHARE_TYPE_GROUP) {
442
			if (!$this->shareManager->allowGroupSharing()) {
443
				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
444
			}
445
446
			// Valid group is required to share
447
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
448
				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
449
			}
450
			$share->setSharedWith($shareWith);
451
			$share->setPermissions($permissions);
452
		} else if ($shareType === Share::SHARE_TYPE_LINK) {
453
			//Can we even share links?
454
			if (!$this->shareManager->shareApiAllowLinks()) {
455
				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
456
			}
457
458
			if ($publicUpload === 'true') {
459
				// Check if public upload is allowed
460
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
461
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
462
				}
463
464
				// Public upload can only be set for folders
465
				if ($path instanceof \OCP\Files\File) {
466
					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
467
				}
468
469
				$share->setPermissions(
470
					Constants::PERMISSION_READ |
471
					Constants::PERMISSION_CREATE |
472
					Constants::PERMISSION_UPDATE |
473
					Constants::PERMISSION_DELETE
474
				);
475
			} else {
476
				$share->setPermissions(Constants::PERMISSION_READ);
477
			}
478
479
			// Set password
480
			if ($password !== '') {
481
				$share->setPassword($password);
482
			}
483
484
485
			if (!empty($label)) {
486
				$share->setLabel($label);
487
			}
488
489
			if ($sendPasswordByTalk === 'true') {
490
				if (!$this->appManager->isEnabledForUser('spreed')) {
491
					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
492
				}
493
494
				$share->setSendPasswordByTalk(true);
495
			}
496
497
			//Expire date
498
			if ($expireDate !== '') {
499
				try {
500
					$expireDate = $this->parseDate($expireDate);
501
					$share->setExpirationDate($expireDate);
502
				} catch (\Exception $e) {
503
					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
504
				}
505
			}
506
507
		} else if ($shareType === Share::SHARE_TYPE_REMOTE) {
508
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
509
				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
510
			}
511
512
			$share->setSharedWith($shareWith);
513
			$share->setPermissions($permissions);
514
		}  else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
515
			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
516
				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
517
			}
518
519
			$share->setSharedWith($shareWith);
520
			$share->setPermissions($permissions);
521
		} else if ($shareType === Share::SHARE_TYPE_EMAIL) {
522
			if ($share->getNodeType() === 'file') {
523
				$share->setPermissions(Constants::PERMISSION_READ);
524
			} else {
525
				$share->setPermissions($permissions);
526
			}
527
			$share->setSharedWith($shareWith);
528
529
			if ($sendPasswordByTalk === 'true') {
530
				if (!$this->appManager->isEnabledForUser('spreed')) {
531
					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
532
				}
533
534
				$share->setSendPasswordByTalk(true);
535
			}
536
		} else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
537
			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
538
				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
539
			}
540
541
			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
0 ignored issues
show
Bug introduced by
The type OCA\Circles\Api\v1\Circles was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
542
543
			// Valid circle is required to share
544
			if ($circle === null) {
545
				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
546
			}
547
			$share->setSharedWith($shareWith);
548
			$share->setPermissions($permissions);
549
		} else if ($shareType === Share::SHARE_TYPE_ROOM) {
550
			try {
551
				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
552
			} catch (QueryException $e) {
553
				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
554
			}
555
		} else {
556
			throw new OCSBadRequestException($this->l->t('Unknown share type'));
557
		}
558
559
		$share->setShareType($shareType);
560
		$share->setSharedBy($this->currentUser);
561
562
		try {
563
			$share = $this->shareManager->createShare($share);
564
		} catch (GenericShareException $e) {
565
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
566
			throw new OCSException($e->getHint(), $code);
567
		} catch (\Exception $e) {
568
			throw new OCSForbiddenException($e->getMessage(), $e);
569
		}
570
571
		$output = $this->formatShare($share);
572
573
		return new DataResponse($output);
574
	}
575
576
	/**
577
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
578
	 * @param boolean $includeTags
579
	 * @return DataResponse
580
	 */
581
	private function getSharedWithMe($node = null, bool $includeTags): DataResponse {
582
583
		$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
584
		$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
585
		$circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
586
		$roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0);
587
588
		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
589
590
		$shares = array_filter($shares, function (IShare $share) {
591
			return $share->getShareOwner() !== $this->currentUser;
592
		});
593
594
		$formatted = [];
595
		foreach ($shares as $share) {
596
			if ($this->canAccessShare($share)) {
597
				try {
598
					$formatted[] = $this->formatShare($share);
599
				} catch (NotFoundException $e) {
600
					// Ignore this share
601
				}
602
			}
603
		}
604
605
		if ($includeTags) {
606
			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
607
		}
608
609
		return new DataResponse($formatted);
610
	}
611
612
	/**
613
	 * @param \OCP\Files\Folder $folder
614
	 * @return DataResponse
615
	 * @throws OCSBadRequestException
616
	 */
617
	private function getSharesInDir(Node $folder): DataResponse {
618
		if (!($folder instanceof \OCP\Files\Folder)) {
619
			throw new OCSBadRequestException($this->l->t('Not a directory'));
620
		}
621
622
		$nodes = $folder->getDirectoryListing();
623
		/** @var \OCP\Share\IShare[] $shares */
624
		$shares = [];
625
		foreach ($nodes as $node) {
626
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, false, -1, 0));
627
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
628
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, false, -1, 0));
629
			if($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
630
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
631
			}
632
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
633
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
634
			}
635
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $node, false, -1, 0));
636
		}
637
638
		$formatted = [];
639
		foreach ($shares as $share) {
640
			try {
641
				$formatted[] = $this->formatShare($share);
642
			} catch (NotFoundException $e) {
643
				//Ignore this share
644
			}
645
		}
646
647
		return new DataResponse($formatted);
648
	}
649
650
	/**
651
	 * The getShares function.
652
	 *
653
	 * @NoAdminRequired
654
	 *
655
	 * @param string $shared_with_me
656
	 * @param string $reshares
657
	 * @param string $subfiles
658
	 * @param string $path
659
	 *
660
	 * - Get shares by the current user
661
	 * - Get shares by the current user and reshares (?reshares=true)
662
	 * - Get shares with the current user (?shared_with_me=true)
663
	 * - Get shares for a specific path (?path=...)
664
	 * - Get all shares in a folder (?subfiles=true&path=..)
665
	 *
666
	 * @return DataResponse
667
	 * @throws OCSNotFoundException
668
	 */
669
	public function getShares(
670
		string $shared_with_me = 'false',
671
		string $reshares = 'false',
672
		string $subfiles = 'false',
673
		string $path = null,
674
		string $include_tags = 'false'
675
	): DataResponse {
676
677
		if ($path !== null) {
678
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
679
			try {
680
				$path = $userFolder->get($path);
681
				$this->lock($path);
682
			} catch (\OCP\Files\NotFoundException $e) {
683
				throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
684
			} catch (LockedException $e) {
685
				throw new OCSNotFoundException($this->l->t('Could not lock path'));
686
			}
687
		}
688
689
		$include_tags = $include_tags === 'true';
690
691
		if ($shared_with_me === 'true') {
692
			$result = $this->getSharedWithMe($path, $include_tags);
693
			return $result;
694
		}
695
696
		if ($subfiles === 'true') {
697
			$result = $this->getSharesInDir($path);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type null; however, parameter $folder of OCA\Files_Sharing\Contro...oller::getSharesInDir() does only seem to accept OCP\Files\Node, maybe add an additional type check? ( Ignorable by Annotation )

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

697
			$result = $this->getSharesInDir(/** @scrutinizer ignore-type */ $path);
Loading history...
698
			return $result;
699
		}
700
701
		if ($reshares === 'true') {
702
			$reshares = true;
703
		} else {
704
			$reshares = false;
705
		}
706
707
		// Get all shares
708
		$userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
709
		$groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
710
		$linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
711
		if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
712
			$mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
713
		} else {
714
			$mailShares = [];
715
		}
716
		if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
717
			$circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
718
		} else {
719
			$circleShares = [];
720
		}
721
		$roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);
722
723
		$shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares);
724
725
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
726
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
727
			$shares = array_merge($shares, $federatedShares);
728
		}
729
730
		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
731
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
732
			$shares = array_merge($shares, $federatedShares);
733
		}
734
735
		$formatted = $miniFormatted = [];
736
		$resharingRight = false;
737
		foreach ($shares as $share) {
738
			/** @var IShare $share */
739
			try {
740
				$format = $this->formatShare($share, $path);
741
				$formatted[] = $format;
742
				if ($share->getSharedBy() === $this->currentUser) {
743
					$miniFormatted[] = $format;
744
				}
745
746
				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $path)) {
747
					$resharingRight = true;
748
				}
749
			} catch (\Exception $e) {
750
				//Ignore share
751
			}
752
		}
753
754
		if (!$resharingRight) {
755
			$formatted = $miniFormatted;
756
		}
757
758
		if ($include_tags) {
759
			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
760
		}
761
762
		return new DataResponse($formatted);
763
	}
764
765
	/**
766
	 * @NoAdminRequired
767
	 *
768
	 * @param string $id
769
	 * @param int $permissions
770
	 * @param string $password
771
	 * @param string $sendPasswordByTalk
772
	 * @param string $publicUpload
773
	 * @param string $expireDate
774
	 * @param string $note
775
	 * @param string $label
776
	 * @param string $hideDownload
777
	 * @return DataResponse
778
	 * @throws LockedException
779
	 * @throws NotFoundException
780
	 * @throws OCSBadRequestException
781
	 * @throws OCSForbiddenException
782
	 * @throws OCSNotFoundException
783
	 */
784
	public function updateShare(
785
		string $id,
786
		int $permissions = null,
787
		string $password = null,
788
		string $sendPasswordByTalk = null,
789
		string $publicUpload = null,
790
		string $expireDate = null,
791
		string $note = null,
792
		string $label = null,
793
		string $hideDownload = null
794
	): DataResponse {
795
		try {
796
			$share = $this->getShareById($id);
797
		} catch (ShareNotFound $e) {
798
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
799
		}
800
801
		$this->lock($share->getNode());
802
803
		if (!$this->canAccessShare($share, false)) {
804
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
805
		}
806
807
		if ($permissions === null &&
808
			$password === null &&
809
			$sendPasswordByTalk === null &&
810
			$publicUpload === null &&
811
			$expireDate === null &&
812
			$note === null &&
813
			$label === null &&
814
			$hideDownload === null
815
		) {
816
			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
817
		}
818
819
		if($note !== null) {
820
			$share->setNote($note);
821
		}
822
823
		/*
824
		 * expirationdate, password and publicUpload only make sense for link shares
825
		 */
826
		if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
827
828
			// Update hide download state
829
			if ($hideDownload === 'true') {
830
				$share->setHideDownload(true);
831
			} else if ($hideDownload === 'false') {
832
				$share->setHideDownload(false);
833
			}
834
835
			$newPermissions = null;
836
			if ($publicUpload === 'true') {
837
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
838
			} else if ($publicUpload === 'false') {
839
				$newPermissions = Constants::PERMISSION_READ;
840
			}
841
842
			if ($permissions !== null) {
843
				$newPermissions = (int)$permissions;
844
				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
845
			}
846
847
			if ($newPermissions !== null &&
848
				!in_array($newPermissions, [
849
					Constants::PERMISSION_READ,
850
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
851
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
852
					Constants::PERMISSION_CREATE, // hidden file list
853
					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
854
				], true)
855
			) {
856
				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
857
			}
858
859
			if (
860
				// legacy
861
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
862
				// correct
863
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
864
			) {
865
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
866
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
867
				}
868
869
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
870
					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
871
				}
872
873
				// normalize to correct public upload permissions
874
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
875
			}
876
877
			if ($newPermissions !== null) {
878
				$share->setPermissions($newPermissions);
879
				$permissions = $newPermissions;
880
			}
881
882
			if ($expireDate === '') {
883
				$share->setExpirationDate(null);
884
			} else if ($expireDate !== null) {
885
				try {
886
					$expireDate = $this->parseDate($expireDate);
887
				} catch (\Exception $e) {
888
					throw new OCSBadRequestException($e->getMessage(), $e);
889
				}
890
				$share->setExpirationDate($expireDate);
891
			}
892
893
			if ($password === '') {
894
				$share->setPassword(null);
895
			} else if ($password !== null) {
896
				$share->setPassword($password);
897
			}
898
899
			if ($label !== null) {
900
				$share->setLabel($label);
901
			}
902
903
			if ($sendPasswordByTalk === 'true') {
904
				if (!$this->appManager->isEnabledForUser('spreed')) {
905
					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
906
				}
907
908
				$share->setSendPasswordByTalk(true);
909
			} else if ($sendPasswordByTalk !== null) {
910
				$share->setSendPasswordByTalk(false);
911
			}
912
		} else {
913
			if ($permissions !== null) {
914
				$permissions = (int)$permissions;
915
				$share->setPermissions($permissions);
916
			}
917
918
			if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
919
				if ($password === '') {
920
					$share->setPassword(null);
921
				} else if ($password !== null) {
922
					$share->setPassword($password);
923
				}
924
925
				if ($sendPasswordByTalk === 'true') {
926
					if (!$this->appManager->isEnabledForUser('spreed')) {
927
						throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
928
					}
929
930
					$share->setSendPasswordByTalk(true);
931
				} else {
932
					$share->setSendPasswordByTalk(false);
933
				}
934
			}
935
936
			if ($expireDate === '') {
937
				$share->setExpirationDate(null);
938
			} else if ($expireDate !== null) {
939
				try {
940
					$expireDate = $this->parseDate($expireDate);
941
				} catch (\Exception $e) {
942
					throw new OCSBadRequestException($e->getMessage(), $e);
943
				}
944
				$share->setExpirationDate($expireDate);
945
			}
946
947
		}
948
949
		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) {
950
			/* Check if this is an incomming share */
951
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
952
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
953
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $share->getNode(), -1, 0));
954
955
			/** @var \OCP\Share\IShare[] $incomingShares */
956
			if (!empty($incomingShares)) {
957
				$maxPermissions = 0;
958
				foreach ($incomingShares as $incomingShare) {
959
					$maxPermissions |= $incomingShare->getPermissions();
960
				}
961
962
				if ($share->getPermissions() & ~$maxPermissions) {
963
					throw new OCSNotFoundException($this->l->t('Cannot increase permissions'));
964
				}
965
			}
966
		}
967
968
969
		try {
970
			$share = $this->shareManager->updateShare($share);
971
		} catch (\Exception $e) {
972
			throw new OCSBadRequestException($e->getMessage(), $e);
973
		}
974
975
		return new DataResponse($this->formatShare($share));
976
	}
977
978
	/**
979
	 * @suppress PhanUndeclaredClassMethod
980
	 */
981
	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
982
		// A file with permissions 0 can't be accessed by us. So Don't show it
983
		if ($share->getPermissions() === 0) {
984
			return false;
985
		}
986
987
		// Owner of the file and the sharer of the file can always get share
988
		if ($share->getShareOwner() === $this->currentUser ||
989
			$share->getSharedBy() === $this->currentUser
990
		) {
991
			return true;
992
		}
993
994
		// If the share is shared with you (or a group you are a member of)
995
		if ($share->getShareType() === Share::SHARE_TYPE_USER &&
996
			$share->getSharedWith() === $this->currentUser
997
		) {
998
			return true;
999
		}
1000
1001
		if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
1002
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1003
			$user = $this->userManager->get($this->currentUser);
1004
			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1005
				return true;
1006
			}
1007
		}
1008
1009
		if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
1010
			// TODO: have a sanity check like above?
1011
			return true;
1012
		}
1013
1014
		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1015
			try {
1016
				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1017
			} catch (QueryException $e) {
1018
				return false;
1019
			}
1020
		}
1021
1022
		return false;
1023
	}
1024
1025
	/**
1026
	 * Make sure that the passed date is valid ISO 8601
1027
	 * So YYYY-MM-DD
1028
	 * If not throw an exception
1029
	 *
1030
	 * @param string $expireDate
1031
	 *
1032
	 * @throws \Exception
1033
	 * @return \DateTime
1034
	 */
1035
	private function parseDate(string $expireDate): \DateTime {
1036
		try {
1037
			$date = new \DateTime($expireDate);
1038
		} catch (\Exception $e) {
1039
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1040
		}
1041
1042
		if ($date === false) {
0 ignored issues
show
introduced by
The condition $date === false is always false.
Loading history...
1043
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1044
		}
1045
1046
		$date->setTime(0, 0, 0);
1047
1048
		return $date;
1049
	}
1050
1051
	/**
1052
	 * Since we have multiple providers but the OCS Share API v1 does
1053
	 * not support this we need to check all backends.
1054
	 *
1055
	 * @param string $id
1056
	 * @return \OCP\Share\IShare
1057
	 * @throws ShareNotFound
1058
	 */
1059
	private function getShareById(string $id): IShare {
1060
		$share = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $share is dead and can be removed.
Loading history...
1061
1062
		// First check if it is an internal share.
1063
		try {
1064
			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1065
			return $share;
1066
		} catch (ShareNotFound $e) {
1067
			// Do nothing, just try the other share type
1068
		}
1069
1070
1071
		try {
1072
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
1073
				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1074
				return $share;
1075
			}
1076
		} catch (ShareNotFound $e) {
1077
			// Do nothing, just try the other share type
1078
		}
1079
1080
		try {
1081
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
1082
				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1083
				return $share;
1084
			}
1085
		} catch (ShareNotFound $e) {
1086
			// Do nothing, just try the other share type
1087
		}
1088
1089
		try {
1090
			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1091
			return $share;
1092
		} catch (ShareNotFound $e) {
1093
			// Do nothing, just try the other share type
1094
		}
1095
1096
		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1097
			throw new ShareNotFound();
1098
		}
1099
		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1100
1101
		return $share;
1102
	}
1103
1104
	/**
1105
	 * Lock a Node
1106
	 *
1107
	 * @param \OCP\Files\Node $node
1108
	 * @throws LockedException
1109
	 */
1110
	private function lock(\OCP\Files\Node $node) {
1111
		$node->lock(ILockingProvider::LOCK_SHARED);
1112
		$this->lockedNode = $node;
1113
	}
1114
1115
	/**
1116
	 * Cleanup the remaining locks
1117
	 * @throws @LockedException
1118
	 */
1119
	public function cleanup() {
1120
		if ($this->lockedNode !== null) {
1121
			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1122
		}
1123
	}
1124
1125
	/**
1126
	 * Returns the helper of ShareAPIController for room shares.
1127
	 *
1128
	 * If the Talk application is not enabled or the helper is not available
1129
	 * a QueryException is thrown instead.
1130
	 *
1131
	 * @return \OCA\Spreed\Share\Helper\ShareAPIController
0 ignored issues
show
Bug introduced by
The type OCA\Spreed\Share\Helper\ShareAPIController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1132
	 * @throws QueryException
1133
	 */
1134
	private function getRoomShareHelper() {
1135
		if (!$this->appManager->isEnabledForUser('spreed')) {
1136
			throw new QueryException();
1137
		}
1138
1139
		return $this->serverContainer->query('\OCA\Spreed\Share\Helper\ShareAPIController');
1140
	}
1141
1142
1143
	/**
1144
	 * Returns if we can find resharing rights in an IShare object for a specific user.
1145
	 *
1146
	 * @suppress PhanUndeclaredClassMethod
1147
	 *
1148
	 * @param string $userId
1149
	 * @param IShare $share
1150
	 * @param Node $node
1151
	 * @return bool
1152
	 * @throws NotFoundException
1153
	 * @throws \OCP\Files\InvalidPathException
1154
	 */
1155
	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1156
1157
		if ($share->getShareOwner() === $userId) {
1158
			return true;
1159
		}
1160
1161
		// we check that current user have parent resharing rights on the current file
1162
		if ($node !== null && ($node->getPermissions() & \OCP\Constants::PERMISSION_SHARE) !== 0) {
1163
			return true;
1164
		}
1165
1166
		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1167
			return false;
1168
		}
1169
1170
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {
1171
			return true;
1172
		}
1173
1174
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1175
			return true;
1176
		}
1177
1178
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles') &&
1179
			class_exists('\OCA\Circles\Api\v1\Circles')) {
1180
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1181
			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1182
			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1183
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
1184
				$shareWithLength = -1;
1185
			}
1186
			$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1187
			try {
1188
				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1189
				if ($member->getLevel() >= 4) {
1190
					return true;
1191
				}
1192
				return false;
1193
			} catch (QueryException $e) {
1194
				return false;
1195
			}
1196
		}
1197
1198
		return false;
1199
	}
1200
1201
}
1202