Passed
Push — master ( b36584...4491ed )
by Roeland
09:59
created

ShareAPIController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 12
dl 0
loc 27
rs 9.8666
c 0
b 0
f 0

How to fix   Many Parameters   

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
			// "share_with" and "share_with_displayname" for passwords of link
212
			// shares was deprecated in Nextcloud 15, use "password" instead.
213
			$result['share_with'] = $share->getPassword();
214
			$result['share_with_displayname'] = $share->getPassword();
215
216
			$result['password'] = $share->getPassword();
217
218
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
219
220
			$result['token'] = $share->getToken();
221
			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
222
223
		} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {
224
			$result['share_with'] = $share->getSharedWith();
225
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
226
			$result['token'] = $share->getToken();
227
		} else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
228
			$result['share_with'] = $share->getSharedWith();
229
			$result['password'] = $share->getPassword();
230
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
231
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
232
			$result['token'] = $share->getToken();
233
		} else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
234
			// getSharedWith() returns either "name (type, owner)" or
235
			// "name (type, owner) [id]", depending on the Circles app version.
236
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
237
238
			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
239
			if (empty($result['share_with_displayname'])) {
240
				$displayNameLength = ($hasCircleId? strrpos($share->getSharedWith(), ' '): strlen($share->getSharedWith()));
241
				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
242
			}
243
244
			$result['share_with_avatar'] = $share->getSharedWithAvatar();
245
246
			$shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0);
247
			$shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' '));
248
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
249
				$shareWithLength = -1;
250
			}
251
			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
252
		} else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
253
			$result['share_with'] = $share->getSharedWith();
254
			$result['share_with_displayname'] = '';
255
256
			try {
257
				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
258
			} catch (QueryException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
259
			}
260
		}
261
262
263
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
264
		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
265
266
		return $result;
267
	}
268
269
	/**
270
	 * Check if one of the users address books knows the exact property, if
271
	 * yes we return the full name.
272
	 *
273
	 * @param string $query
274
	 * @param string $property
275
	 * @return string
276
	 */
277
	private function getDisplayNameFromAddressBook(string $query, string $property): string {
278
		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
279
		$result = \OC::$server->getContactsManager()->search($query, [$property]);
280
		foreach ($result as $r) {
281
			foreach($r[$property] as $value) {
282
				if ($value === $query) {
283
					return $r['FN'];
284
				}
285
			}
286
		}
287
288
		return $query;
289
	}
290
291
	/**
292
	 * Get a specific share by id
293
	 *
294
	 * @NoAdminRequired
295
	 *
296
	 * @param string $id
297
	 * @return DataResponse
298
	 * @throws OCSNotFoundException
299
	 */
300
	public function getShare(string $id): DataResponse {
301
		try {
302
			$share = $this->getShareById($id);
303
		} catch (ShareNotFound $e) {
304
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
305
		}
306
307
		if ($this->canAccessShare($share)) {
308
			try {
309
				$share = $this->formatShare($share);
310
				return new DataResponse([$share]);
311
			} catch (NotFoundException $e) {
312
				//Fall trough
313
			}
314
		}
315
316
		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
317
	}
318
319
	/**
320
	 * Delete a share
321
	 *
322
	 * @NoAdminRequired
323
	 *
324
	 * @param string $id
325
	 * @return DataResponse
326
	 * @throws OCSNotFoundException
327
	 */
328
	public function deleteShare(string $id): DataResponse {
329
		try {
330
			$share = $this->getShareById($id);
331
		} catch (ShareNotFound $e) {
332
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
333
		}
334
335
		try {
336
			$this->lock($share->getNode());
337
		} catch (LockedException $e) {
338
			throw new OCSNotFoundException($this->l->t('could not delete share'));
339
		}
340
341
		if (!$this->canAccessShare($share)) {
342
			throw new OCSNotFoundException($this->l->t('Could not delete share'));
343
		}
344
345
		if (($share->getShareType() === Share::SHARE_TYPE_GROUP ||
346
				$share->getShareType() === Share::SHARE_TYPE_ROOM) &&
347
			$share->getShareOwner() !== $this->currentUser &&
348
			$share->getSharedBy() !== $this->currentUser) {
349
			$this->shareManager->deleteFromSelf($share, $this->currentUser);
350
		} else {
351
			$this->shareManager->deleteShare($share);
352
		}
353
354
		return new DataResponse();
355
	}
356
357
	/**
358
	 * @NoAdminRequired
359
	 *
360
	 * @param string $path
361
	 * @param int $permissions
362
	 * @param int $shareType
363
	 * @param string $shareWith
364
	 * @param string $publicUpload
365
	 * @param string $password
366
	 * @param string $sendPasswordByTalk
367
	 * @param string $expireDate
368
	 * @param string $label
369
	 *
370
	 * @return DataResponse
371
	 * @throws NotFoundException
372
	 * @throws OCSBadRequestException
373
	 * @throws OCSException
374
	 * @throws OCSForbiddenException
375
	 * @throws OCSNotFoundException
376
	 * @throws \OCP\Files\InvalidPathException
377
	 * @suppress PhanUndeclaredClassMethod
378
	 */
379
	public function createShare(
380
		string $path = null,
381
		int $permissions = null,
382
		int $shareType = -1,
383
		string $shareWith = null,
384
		string $publicUpload = 'false',
385
		string $password = '',
386
		string $sendPasswordByTalk = null,
387
		string $expireDate = '',
388
		string $label = ''
389
	): DataResponse {
390
		$share = $this->shareManager->newShare();
391
392
		if ($permissions === null) {
393
			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
394
		}
395
396
		// Verify path
397
		if ($path === null) {
398
			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
399
		}
400
401
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
402
		try {
403
			$path = $userFolder->get($path);
404
		} catch (NotFoundException $e) {
405
			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
406
		}
407
408
		$share->setNode($path);
409
410
		try {
411
			$this->lock($share->getNode());
412
		} catch (LockedException $e) {
413
			throw new OCSNotFoundException($this->l->t('Could not create share'));
414
		}
415
416
		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
417
			throw new OCSNotFoundException($this->l->t('invalid permissions'));
418
		}
419
420
		// Shares always require read permissions
421
		$permissions |= Constants::PERMISSION_READ;
422
423
		if ($path instanceof \OCP\Files\File) {
424
			// Single file shares should never have delete or create permissions
425
			$permissions &= ~Constants::PERMISSION_DELETE;
426
			$permissions &= ~Constants::PERMISSION_CREATE;
427
		}
428
429
		/*
430
		 * Hack for https://github.com/owncloud/core/issues/22587
431
		 * We check the permissions via webdav. But the permissions of the mount point
432
		 * do not equal the share permissions. Here we fix that for federated mounts.
433
		 */
434
		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
435
			$permissions &= ~($permissions & ~$path->getPermissions());
436
		}
437
438
		if ($shareType === Share::SHARE_TYPE_USER) {
439
			// Valid user is required to share
440
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
441
				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
442
			}
443
			$share->setSharedWith($shareWith);
444
			$share->setPermissions($permissions);
445
		} else if ($shareType === Share::SHARE_TYPE_GROUP) {
446
			if (!$this->shareManager->allowGroupSharing()) {
447
				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
448
			}
449
450
			// Valid group is required to share
451
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
452
				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
453
			}
454
			$share->setSharedWith($shareWith);
455
			$share->setPermissions($permissions);
456
		} else if ($shareType === Share::SHARE_TYPE_LINK) {
457
			//Can we even share links?
458
			if (!$this->shareManager->shareApiAllowLinks()) {
459
				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
460
			}
461
462
			if ($publicUpload === 'true') {
463
				// Check if public upload is allowed
464
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
465
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
466
				}
467
468
				// Public upload can only be set for folders
469
				if ($path instanceof \OCP\Files\File) {
470
					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
471
				}
472
473
				$share->setPermissions(
474
					Constants::PERMISSION_READ |
475
					Constants::PERMISSION_CREATE |
476
					Constants::PERMISSION_UPDATE |
477
					Constants::PERMISSION_DELETE
478
				);
479
			} else {
480
				$share->setPermissions(Constants::PERMISSION_READ);
481
			}
482
483
			// Set password
484
			if ($password !== '') {
485
				$share->setPassword($password);
486
			}
487
488
489
			if (!empty($label)) {
490
				$share->setLabel($label);
491
			}
492
493
			if ($sendPasswordByTalk === 'true') {
494
				if (!$this->appManager->isEnabledForUser('spreed')) {
495
					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
496
				}
497
498
				$share->setSendPasswordByTalk(true);
499
			}
500
501
			//Expire date
502
			if ($expireDate !== '') {
503
				try {
504
					$expireDate = $this->parseDate($expireDate);
505
					$share->setExpirationDate($expireDate);
506
				} catch (\Exception $e) {
507
					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
508
				}
509
			}
510
511
		} else if ($shareType === Share::SHARE_TYPE_REMOTE) {
512
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
513
				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]));
514
			}
515
516
			$share->setSharedWith($shareWith);
517
			$share->setPermissions($permissions);
518
		}  else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
519
			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
520
				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]));
521
			}
522
523
			$share->setSharedWith($shareWith);
524
			$share->setPermissions($permissions);
525
		} else if ($shareType === Share::SHARE_TYPE_EMAIL) {
526
			if ($share->getNodeType() === 'file') {
527
				$share->setPermissions(Constants::PERMISSION_READ);
528
			} else {
529
				$share->setPermissions($permissions);
530
			}
531
			$share->setSharedWith($shareWith);
532
533
			if ($sendPasswordByTalk === 'true') {
534
				if (!$this->appManager->isEnabledForUser('spreed')) {
535
					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
536
				}
537
538
				$share->setSendPasswordByTalk(true);
539
			}
540
		} else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
541
			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
542
				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
543
			}
544
545
			$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...
546
547
			// Valid circle is required to share
548
			if ($circle === null) {
549
				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
550
			}
551
			$share->setSharedWith($shareWith);
552
			$share->setPermissions($permissions);
553
		} else if ($shareType === Share::SHARE_TYPE_ROOM) {
554
			try {
555
				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
556
			} catch (QueryException $e) {
557
				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
558
			}
559
		} else {
560
			throw new OCSBadRequestException($this->l->t('Unknown share type'));
561
		}
562
563
		$share->setShareType($shareType);
564
		$share->setSharedBy($this->currentUser);
565
566
		try {
567
			$share = $this->shareManager->createShare($share);
568
		} catch (GenericShareException $e) {
569
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
570
			throw new OCSException($e->getHint(), $code);
571
		} catch (\Exception $e) {
572
			throw new OCSForbiddenException($e->getMessage(), $e);
573
		}
574
575
		$output = $this->formatShare($share);
576
577
		return new DataResponse($output);
578
	}
579
580
	/**
581
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
582
	 * @param boolean $includeTags
583
	 * @return DataResponse
584
	 */
585
	private function getSharedWithMe($node = null, bool $includeTags): DataResponse {
586
587
		$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
588
		$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
589
		$circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
590
		$roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0);
591
592
		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
593
594
		$shares = array_filter($shares, function (IShare $share) {
595
			return $share->getShareOwner() !== $this->currentUser;
596
		});
597
598
		$formatted = [];
599
		foreach ($shares as $share) {
600
			if ($this->canAccessShare($share)) {
601
				try {
602
					$formatted[] = $this->formatShare($share);
603
				} catch (NotFoundException $e) {
604
					// Ignore this share
605
				}
606
			}
607
		}
608
609
		if ($includeTags) {
610
			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
611
		}
612
613
		return new DataResponse($formatted);
614
	}
615
616
	/**
617
	 * @param \OCP\Files\Folder $folder
618
	 * @return DataResponse
619
	 * @throws OCSBadRequestException
620
	 */
621
	private function getSharesInDir(Node $folder): DataResponse {
622
		if (!($folder instanceof \OCP\Files\Folder)) {
623
			throw new OCSBadRequestException($this->l->t('Not a directory'));
624
		}
625
626
		$nodes = $folder->getDirectoryListing();
627
		/** @var \OCP\Share\IShare[] $shares */
628
		$shares = [];
629
		foreach ($nodes as $node) {
630
631
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, true, -1, 0));
632
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, true, -1, 0));
633
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, true, -1, 0));
634
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
635
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, true, -1, 0));
636
			}
637
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
638
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $node, true, -1, 0));
639
			}
640
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $node, true, -1, 0));
641
		}
642
643
		$formatted = $miniFormatted = [];
644
		$resharingRight = false;
645
		$known = [];
646
		foreach ($shares as $share) {
647
			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
648
				continue;
649
			}
650
651
			try {
652
				$format = $this->formatShare($share);
653
654
				$known[] = $share->getId();
655
				$formatted[] = $format;
656
				if ($share->getSharedBy() === $this->currentUser) {
657
					$miniFormatted[] = $format;
658
				}
659
				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
660
					$resharingRight = true;
661
				}
662
			} catch (\Exception $e) {
663
				//Ignore this share
664
			}
665
		}
666
667
		if (!$resharingRight) {
668
			$formatted = $miniFormatted;
669
		}
670
671
		return new DataResponse($formatted);
672
	}
673
674
	/**
675
	 * The getShares function.
676
	 *
677
	 * @NoAdminRequired
678
	 *
679
	 * @param string $shared_with_me
680
	 * @param string $reshares
681
	 * @param string $subfiles
682
	 * @param string $path
683
	 *
684
	 * - Get shares by the current user
685
	 * - Get shares by the current user and reshares (?reshares=true)
686
	 * - Get shares with the current user (?shared_with_me=true)
687
	 * - Get shares for a specific path (?path=...)
688
	 * - Get all shares in a folder (?subfiles=true&path=..)
689
	 *
690
	 * @return DataResponse
691
	 * @throws OCSNotFoundException
692
	 */
693
	public function getShares(
694
		string $shared_with_me = 'false',
695
		string $reshares = 'false',
696
		string $subfiles = 'false',
697
		string $path = null,
698
		string $include_tags = 'false'
699
	): DataResponse {
700
701
		if ($path !== null) {
702
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
703
			try {
704
				$path = $userFolder->get($path);
705
				$this->lock($path);
706
			} catch (\OCP\Files\NotFoundException $e) {
707
				throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
708
			} catch (LockedException $e) {
709
				throw new OCSNotFoundException($this->l->t('Could not lock path'));
710
			}
711
		}
712
713
		$include_tags = $include_tags === 'true';
714
715
		if ($shared_with_me === 'true') {
716
			$result = $this->getSharedWithMe($path, $include_tags);
717
			return $result;
718
		}
719
720
		if ($subfiles === 'true') {
721
			$result = $this->getSharesInDir($path);
722
			return $result;
723
		}
724
725
		if ($reshares === 'true') {
726
			$reshares = true;
727
		} else {
728
			$reshares = false;
729
		}
730
731
		// Get all shares
732
		$userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
733
		$groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
734
		$linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
735
		if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
736
			$mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
737
		} else {
738
			$mailShares = [];
739
		}
740
		if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
741
			$circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
742
		} else {
743
			$circleShares = [];
744
		}
745
		$roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);
746
747
		$shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares);
748
749
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
750
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
751
			$shares = array_merge($shares, $federatedShares);
752
		}
753
754
		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
755
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
756
			$shares = array_merge($shares, $federatedShares);
757
		}
758
759
		$formatted = $miniFormatted = [];
760
		$resharingRight = false;
761
		foreach ($shares as $share) {
762
			/** @var IShare $share */
763
			try {
764
				$format = $this->formatShare($share, $path);
765
				$formatted[] = $format;
766
				if ($share->getSharedBy() === $this->currentUser) {
767
					$miniFormatted[] = $format;
768
				}
769
770
				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $path)) {
771
					$resharingRight = true;
772
				}
773
			} catch (\Exception $e) {
774
				//Ignore share
775
			}
776
		}
777
778
		if (!$resharingRight) {
779
			$formatted = $miniFormatted;
780
		}
781
782
		if ($include_tags) {
783
			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
784
		}
785
786
		return new DataResponse($formatted);
787
	}
788
789
	/**
790
	 * @NoAdminRequired
791
	 *
792
	 * @param string $id
793
	 * @param int $permissions
794
	 * @param string $password
795
	 * @param string $sendPasswordByTalk
796
	 * @param string $publicUpload
797
	 * @param string $expireDate
798
	 * @param string $note
799
	 * @param string $label
800
	 * @param string $hideDownload
801
	 * @return DataResponse
802
	 * @throws LockedException
803
	 * @throws NotFoundException
804
	 * @throws OCSBadRequestException
805
	 * @throws OCSForbiddenException
806
	 * @throws OCSNotFoundException
807
	 */
808
	public function updateShare(
809
		string $id,
810
		int $permissions = null,
811
		string $password = null,
812
		string $sendPasswordByTalk = null,
813
		string $publicUpload = null,
814
		string $expireDate = null,
815
		string $note = null,
816
		string $label = null,
817
		string $hideDownload = null
818
	): DataResponse {
819
		try {
820
			$share = $this->getShareById($id);
821
		} catch (ShareNotFound $e) {
822
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
823
		}
824
825
		$this->lock($share->getNode());
826
827
		if (!$this->canAccessShare($share, false)) {
828
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
829
		}
830
831
		if ($share->getShareOwner() !== $this->currentUser && $share->getSharedBy() !== $this->currentUser) {
832
			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
833
		}
834
835
		if ($permissions === null &&
836
			$password === null &&
837
			$sendPasswordByTalk === null &&
838
			$publicUpload === null &&
839
			$expireDate === null &&
840
			$note === null &&
841
			$label === null &&
842
			$hideDownload === null
843
		) {
844
			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
845
		}
846
847
		if($note !== null) {
848
			$share->setNote($note);
849
		}
850
851
		/*
852
		 * expirationdate, password and publicUpload only make sense for link shares
853
		 */
854
		if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
855
856
			// Update hide download state
857
			if ($hideDownload === 'true') {
858
				$share->setHideDownload(true);
859
			} else if ($hideDownload === 'false') {
860
				$share->setHideDownload(false);
861
			}
862
863
			$newPermissions = null;
864
			if ($publicUpload === 'true') {
865
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
866
			} else if ($publicUpload === 'false') {
867
				$newPermissions = Constants::PERMISSION_READ;
868
			}
869
870
			if ($permissions !== null) {
871
				$newPermissions = (int)$permissions;
872
				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
873
			}
874
875
			if ($newPermissions !== null &&
876
				!in_array($newPermissions, [
877
					Constants::PERMISSION_READ,
878
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
879
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
880
					Constants::PERMISSION_CREATE, // hidden file list
881
					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
882
				], true)
883
			) {
884
				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
885
			}
886
887
			if (
888
				// legacy
889
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
890
				// correct
891
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
892
			) {
893
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
894
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
895
				}
896
897
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
898
					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
899
				}
900
901
				// normalize to correct public upload permissions
902
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
903
			}
904
905
			if ($newPermissions !== null) {
906
				$share->setPermissions($newPermissions);
907
				$permissions = $newPermissions;
908
			}
909
910
			if ($expireDate === '') {
911
				$share->setExpirationDate(null);
912
			} else if ($expireDate !== null) {
913
				try {
914
					$expireDate = $this->parseDate($expireDate);
915
				} catch (\Exception $e) {
916
					throw new OCSBadRequestException($e->getMessage(), $e);
917
				}
918
				$share->setExpirationDate($expireDate);
919
			}
920
921
			if ($password === '') {
922
				$share->setPassword(null);
923
			} else if ($password !== null) {
924
				$share->setPassword($password);
925
			}
926
927
			if ($label !== null) {
928
				$share->setLabel($label);
929
			}
930
931
			if ($sendPasswordByTalk === 'true') {
932
				if (!$this->appManager->isEnabledForUser('spreed')) {
933
					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
934
				}
935
936
				$share->setSendPasswordByTalk(true);
937
			} else if ($sendPasswordByTalk !== null) {
938
				$share->setSendPasswordByTalk(false);
939
			}
940
		} else {
941
			if ($permissions !== null) {
942
				$permissions = (int)$permissions;
943
				$share->setPermissions($permissions);
944
			}
945
946
			if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
947
				if ($password === '') {
948
					$share->setPassword(null);
949
				} else if ($password !== null) {
950
					$share->setPassword($password);
951
				}
952
953
				if ($sendPasswordByTalk === 'true') {
954
					if (!$this->appManager->isEnabledForUser('spreed')) {
955
						throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
956
					}
957
958
					$share->setSendPasswordByTalk(true);
959
				} else {
960
					$share->setSendPasswordByTalk(false);
961
				}
962
			}
963
964
			if ($expireDate === '') {
965
				$share->setExpirationDate(null);
966
			} else if ($expireDate !== null) {
967
				try {
968
					$expireDate = $this->parseDate($expireDate);
969
				} catch (\Exception $e) {
970
					throw new OCSBadRequestException($e->getMessage(), $e);
971
				}
972
				$share->setExpirationDate($expireDate);
973
			}
974
975
		}
976
977
		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) {
978
			/* Check if this is an incoming share */
979
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
980
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
981
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $share->getNode(), -1, 0));
982
983
			/** @var \OCP\Share\IShare[] $incomingShares */
984
			if (!empty($incomingShares)) {
985
				$maxPermissions = 0;
986
				foreach ($incomingShares as $incomingShare) {
987
					$maxPermissions |= $incomingShare->getPermissions();
988
				}
989
990
				if ($share->getPermissions() & ~$maxPermissions) {
991
					throw new OCSNotFoundException($this->l->t('Cannot increase permissions'));
992
				}
993
			}
994
		}
995
996
997
		try {
998
			$share = $this->shareManager->updateShare($share);
999
		} catch (\Exception $e) {
1000
			throw new OCSBadRequestException($e->getMessage(), $e);
1001
		}
1002
1003
		return new DataResponse($this->formatShare($share));
1004
	}
1005
1006
	/**
1007
	 * @suppress PhanUndeclaredClassMethod
1008
	 */
1009
	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1010
		// A file with permissions 0 can't be accessed by us. So Don't show it
1011
		if ($share->getPermissions() === 0) {
1012
			return false;
1013
		}
1014
1015
		// Owner of the file and the sharer of the file can always get share
1016
		if ($share->getShareOwner() === $this->currentUser ||
1017
			$share->getSharedBy() === $this->currentUser
1018
		) {
1019
			return true;
1020
		}
1021
1022
		// If the share is shared with you (or a group you are a member of)
1023
		if ($share->getShareType() === Share::SHARE_TYPE_USER &&
1024
			$share->getSharedWith() === $this->currentUser
1025
		) {
1026
			return true;
1027
		}
1028
1029
		if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
1030
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1031
			$user = $this->userManager->get($this->currentUser);
1032
			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1033
				return true;
1034
			}
1035
		}
1036
1037
		if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
1038
			// TODO: have a sanity check like above?
1039
			return true;
1040
		}
1041
1042
		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1043
			try {
1044
				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1045
			} catch (QueryException $e) {
1046
				return false;
1047
			}
1048
		}
1049
1050
		return false;
1051
	}
1052
1053
	/**
1054
	 * Make sure that the passed date is valid ISO 8601
1055
	 * So YYYY-MM-DD
1056
	 * If not throw an exception
1057
	 *
1058
	 * @param string $expireDate
1059
	 *
1060
	 * @throws \Exception
1061
	 * @return \DateTime
1062
	 */
1063
	private function parseDate(string $expireDate): \DateTime {
1064
		try {
1065
			$date = new \DateTime($expireDate);
1066
		} catch (\Exception $e) {
1067
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1068
		}
1069
1070
		if ($date === false) {
0 ignored issues
show
introduced by
The condition $date === false is always false.
Loading history...
1071
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1072
		}
1073
1074
		$date->setTime(0, 0, 0);
1075
1076
		return $date;
1077
	}
1078
1079
	/**
1080
	 * Since we have multiple providers but the OCS Share API v1 does
1081
	 * not support this we need to check all backends.
1082
	 *
1083
	 * @param string $id
1084
	 * @return \OCP\Share\IShare
1085
	 * @throws ShareNotFound
1086
	 */
1087
	private function getShareById(string $id): IShare {
1088
		$share = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $share is dead and can be removed.
Loading history...
1089
1090
		// First check if it is an internal share.
1091
		try {
1092
			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1093
			return $share;
1094
		} catch (ShareNotFound $e) {
1095
			// Do nothing, just try the other share type
1096
		}
1097
1098
1099
		try {
1100
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
1101
				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1102
				return $share;
1103
			}
1104
		} catch (ShareNotFound $e) {
1105
			// Do nothing, just try the other share type
1106
		}
1107
1108
		try {
1109
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
1110
				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1111
				return $share;
1112
			}
1113
		} catch (ShareNotFound $e) {
1114
			// Do nothing, just try the other share type
1115
		}
1116
1117
		try {
1118
			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1119
			return $share;
1120
		} catch (ShareNotFound $e) {
1121
			// Do nothing, just try the other share type
1122
		}
1123
1124
		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1125
			throw new ShareNotFound();
1126
		}
1127
		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1128
1129
		return $share;
1130
	}
1131
1132
	/**
1133
	 * Lock a Node
1134
	 *
1135
	 * @param \OCP\Files\Node $node
1136
	 * @throws LockedException
1137
	 */
1138
	private function lock(\OCP\Files\Node $node) {
1139
		$node->lock(ILockingProvider::LOCK_SHARED);
1140
		$this->lockedNode = $node;
1141
	}
1142
1143
	/**
1144
	 * Cleanup the remaining locks
1145
	 * @throws @LockedException
1146
	 */
1147
	public function cleanup() {
1148
		if ($this->lockedNode !== null) {
1149
			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1150
		}
1151
	}
1152
1153
	/**
1154
	 * Returns the helper of ShareAPIController for room shares.
1155
	 *
1156
	 * If the Talk application is not enabled or the helper is not available
1157
	 * a QueryException is thrown instead.
1158
	 *
1159
	 * @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...
1160
	 * @throws QueryException
1161
	 */
1162
	private function getRoomShareHelper() {
1163
		if (!$this->appManager->isEnabledForUser('spreed')) {
1164
			throw new QueryException();
1165
		}
1166
1167
		return $this->serverContainer->query('\OCA\Spreed\Share\Helper\ShareAPIController');
1168
	}
1169
1170
1171
	/**
1172
	 * Returns if we can find resharing rights in an IShare object for a specific user.
1173
	 *
1174
	 * @suppress PhanUndeclaredClassMethod
1175
	 *
1176
	 * @param string $userId
1177
	 * @param IShare $share
1178
	 * @param Node $node
1179
	 * @return bool
1180
	 * @throws NotFoundException
1181
	 * @throws \OCP\Files\InvalidPathException
1182
	 */
1183
	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1184
1185
		if ($share->getShareOwner() === $userId) {
1186
			return true;
1187
		}
1188
1189
		// we check that current user have parent resharing rights on the current file
1190
		if ($node !== null && ($node->getPermissions() & \OCP\Constants::PERMISSION_SHARE) !== 0) {
1191
			return true;
1192
		}
1193
1194
		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1195
			return false;
1196
		}
1197
1198
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {
1199
			return true;
1200
		}
1201
1202
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1203
			return true;
1204
		}
1205
1206
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles') &&
1207
			class_exists('\OCA\Circles\Api\v1\Circles')) {
1208
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1209
			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1210
			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1211
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
1212
				$shareWithLength = -1;
1213
			}
1214
			$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1215
			try {
1216
				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1217
				if ($member->getLevel() >= 4) {
1218
					return true;
1219
				}
1220
				return false;
1221
			} catch (QueryException $e) {
1222
				return false;
1223
			}
1224
		}
1225
1226
		return false;
1227
	}
1228
1229
}
1230