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

ShareAPIController::getSharesInDir()   C

Complexity

Conditions 13
Paths 131

Size

Total Lines 51
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 31
nc 131
nop 1
dl 0
loc 51
rs 6.3583
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
			// "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