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

ShareAPIController::getShares()   F

Complexity

Conditions 18
Paths 2824

Size

Total Lines 94
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 55
nc 2824
nop 5
dl 0
loc 94
rs 0.7
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

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