Passed
Push — master ( 39bee7...b56d7f )
by Julius
13:15 queued 10s
created
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +1697 added lines, -1697 removed lines patch added patch discarded remove patch
@@ -83,1704 +83,1704 @@
 block discarded – undo
83 83
  */
84 84
 class ShareAPIController extends OCSController {
85 85
 
86
-	/** @var IManager */
87
-	private $shareManager;
88
-	/** @var IGroupManager */
89
-	private $groupManager;
90
-	/** @var IUserManager */
91
-	private $userManager;
92
-	/** @var IRootFolder */
93
-	private $rootFolder;
94
-	/** @var IURLGenerator */
95
-	private $urlGenerator;
96
-	/** @var string */
97
-	private $currentUser;
98
-	/** @var IL10N */
99
-	private $l;
100
-	/** @var \OCP\Files\Node */
101
-	private $lockedNode;
102
-	/** @var IConfig */
103
-	private $config;
104
-	/** @var IAppManager */
105
-	private $appManager;
106
-	/** @var IServerContainer */
107
-	private $serverContainer;
108
-	/** @var IUserStatusManager */
109
-	private $userStatusManager;
110
-	/** @var IPreview */
111
-	private $previewManager;
112
-
113
-	/**
114
-	 * Share20OCS constructor.
115
-	 *
116
-	 * @param string $appName
117
-	 * @param IRequest $request
118
-	 * @param IManager $shareManager
119
-	 * @param IGroupManager $groupManager
120
-	 * @param IUserManager $userManager
121
-	 * @param IRootFolder $rootFolder
122
-	 * @param IURLGenerator $urlGenerator
123
-	 * @param string $userId
124
-	 * @param IL10N $l10n
125
-	 * @param IConfig $config
126
-	 * @param IAppManager $appManager
127
-	 * @param IServerContainer $serverContainer
128
-	 * @param IUserStatusManager $userStatusManager
129
-	 */
130
-	public function __construct(
131
-		string $appName,
132
-		IRequest $request,
133
-		IManager $shareManager,
134
-		IGroupManager $groupManager,
135
-		IUserManager $userManager,
136
-		IRootFolder $rootFolder,
137
-		IURLGenerator $urlGenerator,
138
-		string $userId = null,
139
-		IL10N $l10n,
140
-		IConfig $config,
141
-		IAppManager $appManager,
142
-		IServerContainer $serverContainer,
143
-		IUserStatusManager $userStatusManager,
144
-		IPreview $previewManager
145
-	) {
146
-		parent::__construct($appName, $request);
147
-
148
-		$this->shareManager = $shareManager;
149
-		$this->userManager = $userManager;
150
-		$this->groupManager = $groupManager;
151
-		$this->request = $request;
152
-		$this->rootFolder = $rootFolder;
153
-		$this->urlGenerator = $urlGenerator;
154
-		$this->currentUser = $userId;
155
-		$this->l = $l10n;
156
-		$this->config = $config;
157
-		$this->appManager = $appManager;
158
-		$this->serverContainer = $serverContainer;
159
-		$this->userStatusManager = $userStatusManager;
160
-		$this->previewManager = $previewManager;
161
-	}
162
-
163
-	/**
164
-	 * Convert an IShare to an array for OCS output
165
-	 *
166
-	 * @param \OCP\Share\IShare $share
167
-	 * @param Node|null $recipientNode
168
-	 * @return array
169
-	 * @throws NotFoundException In case the node can't be resolved.
170
-	 *
171
-	 * @suppress PhanUndeclaredClassMethod
172
-	 */
173
-	protected function formatShare(IShare $share, Node $recipientNode = null): array {
174
-		$sharedBy = $this->userManager->get($share->getSharedBy());
175
-		$shareOwner = $this->userManager->get($share->getShareOwner());
176
-
177
-		$result = [
178
-			'id' => $share->getId(),
179
-			'share_type' => $share->getShareType(),
180
-			'uid_owner' => $share->getSharedBy(),
181
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
182
-			// recipient permissions
183
-			'permissions' => $share->getPermissions(),
184
-			// current user permissions on this share
185
-			'can_edit' => $this->canEditShare($share),
186
-			'can_delete' => $this->canDeleteShare($share),
187
-			'stime' => $share->getShareTime()->getTimestamp(),
188
-			'parent' => null,
189
-			'expiration' => null,
190
-			'token' => null,
191
-			'uid_file_owner' => $share->getShareOwner(),
192
-			'note' => $share->getNote(),
193
-			'label' => $share->getLabel(),
194
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
195
-		];
196
-
197
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
198
-		if ($recipientNode) {
199
-			$node = $recipientNode;
200
-		} else {
201
-			$nodes = $userFolder->getById($share->getNodeId());
202
-			if (empty($nodes)) {
203
-				// fallback to guessing the path
204
-				$node = $userFolder->get($share->getTarget());
205
-				if ($node === null || $share->getTarget() === '') {
206
-					throw new NotFoundException();
207
-				}
208
-			} else {
209
-				$node = reset($nodes);
210
-			}
211
-		}
212
-
213
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
214
-		if ($node instanceof Folder) {
215
-			$result['item_type'] = 'folder';
216
-		} else {
217
-			$result['item_type'] = 'file';
218
-		}
219
-
220
-		$result['mimetype'] = $node->getMimetype();
221
-		$result['has_preview'] = $this->previewManager->isAvailable($node);
222
-		$result['storage_id'] = $node->getStorage()->getId();
223
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
224
-		$result['item_source'] = $node->getId();
225
-		$result['file_source'] = $node->getId();
226
-		$result['file_parent'] = $node->getParent()->getId();
227
-		$result['file_target'] = $share->getTarget();
228
-
229
-		$expiration = $share->getExpirationDate();
230
-		if ($expiration !== null) {
231
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
232
-		}
233
-
234
-		if ($share->getShareType() === IShare::TYPE_USER) {
235
-			$sharedWith = $this->userManager->get($share->getSharedWith());
236
-			$result['share_with'] = $share->getSharedWith();
237
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
238
-			$result['share_with_displayname_unique'] = $sharedWith !== null ? (
239
-				 $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
240
-			) : $share->getSharedWith();
241
-			$result['status'] = [];
242
-
243
-			$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
244
-			$userStatus = array_shift($userStatuses);
245
-			if ($userStatus) {
246
-				$result['status'] = [
247
-					'status' => $userStatus->getStatus(),
248
-					'message' => $userStatus->getMessage(),
249
-					'icon' => $userStatus->getIcon(),
250
-					'clearAt' => $userStatus->getClearAt()
251
-						? (int)$userStatus->getClearAt()->format('U')
252
-						: null,
253
-				];
254
-			}
255
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
256
-			$group = $this->groupManager->get($share->getSharedWith());
257
-			$result['share_with'] = $share->getSharedWith();
258
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
259
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
260
-
261
-			// "share_with" and "share_with_displayname" for passwords of link
262
-			// shares was deprecated in Nextcloud 15, use "password" instead.
263
-			$result['share_with'] = $share->getPassword();
264
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
265
-
266
-			$result['password'] = $share->getPassword();
267
-
268
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
269
-
270
-			$result['token'] = $share->getToken();
271
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
272
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
273
-			$result['share_with'] = $share->getSharedWith();
274
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
275
-			$result['token'] = $share->getToken();
276
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
277
-			$result['share_with'] = $share->getSharedWith();
278
-			$result['password'] = $share->getPassword();
279
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
280
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
281
-			$result['token'] = $share->getToken();
282
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
283
-			// getSharedWith() returns either "name (type, owner)" or
284
-			// "name (type, owner) [id]", depending on the Circles app version.
285
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
286
-
287
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
288
-			if (empty($result['share_with_displayname'])) {
289
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
290
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
291
-			}
292
-
293
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
294
-
295
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
296
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
297
-			if (is_bool($shareWithLength)) {
298
-				$shareWithLength = -1;
299
-			}
300
-			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
301
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
302
-			$result['share_with'] = $share->getSharedWith();
303
-			$result['share_with_displayname'] = '';
304
-
305
-			try {
306
-				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
307
-			} catch (QueryException $e) {
308
-			}
309
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
310
-			$result['share_with'] = $share->getSharedWith();
311
-			$result['share_with_displayname'] = '';
312
-
313
-			try {
314
-				$result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
315
-			} catch (QueryException $e) {
316
-			}
317
-		}
318
-
319
-
320
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
321
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
322
-
323
-		return $result;
324
-	}
325
-
326
-	/**
327
-	 * Check if one of the users address books knows the exact property, if
328
-	 * yes we return the full name.
329
-	 *
330
-	 * @param string $query
331
-	 * @param string $property
332
-	 * @return string
333
-	 */
334
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
335
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
336
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
337
-		foreach ($result as $r) {
338
-			foreach ($r[$property] as $value) {
339
-				if ($value === $query && $r['FN']) {
340
-					return $r['FN'];
341
-				}
342
-			}
343
-		}
344
-
345
-		return $query;
346
-	}
347
-
348
-	/**
349
-	 * Get a specific share by id
350
-	 *
351
-	 * @NoAdminRequired
352
-	 *
353
-	 * @param string $id
354
-	 * @return DataResponse
355
-	 * @throws OCSNotFoundException
356
-	 */
357
-	public function getShare(string $id): DataResponse {
358
-		try {
359
-			$share = $this->getShareById($id);
360
-		} catch (ShareNotFound $e) {
361
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
362
-		}
363
-
364
-		try {
365
-			if ($this->canAccessShare($share)) {
366
-				$share = $this->formatShare($share);
367
-				return new DataResponse([$share]);
368
-			}
369
-		} catch (NotFoundException $e) {
370
-			// Fall trough
371
-		}
372
-
373
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
374
-	}
375
-
376
-	/**
377
-	 * Delete a share
378
-	 *
379
-	 * @NoAdminRequired
380
-	 *
381
-	 * @param string $id
382
-	 * @return DataResponse
383
-	 * @throws OCSNotFoundException
384
-	 */
385
-	public function deleteShare(string $id): DataResponse {
386
-		try {
387
-			$share = $this->getShareById($id);
388
-		} catch (ShareNotFound $e) {
389
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
390
-		}
391
-
392
-		try {
393
-			$this->lock($share->getNode());
394
-		} catch (LockedException $e) {
395
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
396
-		}
397
-
398
-		if (!$this->canAccessShare($share)) {
399
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
400
-		}
401
-
402
-		// if it's a group share or a room share
403
-		// we don't delete the share, but only the
404
-		// mount point. Allowing it to be restored
405
-		// from the deleted shares
406
-		if ($this->canDeleteShareFromSelf($share)) {
407
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
408
-		} else {
409
-			if (!$this->canDeleteShare($share)) {
410
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
411
-			}
412
-
413
-			$this->shareManager->deleteShare($share);
414
-		}
415
-
416
-		return new DataResponse();
417
-	}
418
-
419
-	/**
420
-	 * @NoAdminRequired
421
-	 *
422
-	 * @param string $path
423
-	 * @param int $permissions
424
-	 * @param int $shareType
425
-	 * @param string $shareWith
426
-	 * @param string $publicUpload
427
-	 * @param string $password
428
-	 * @param string $sendPasswordByTalk
429
-	 * @param string $expireDate
430
-	 * @param string $label
431
-	 *
432
-	 * @return DataResponse
433
-	 * @throws NotFoundException
434
-	 * @throws OCSBadRequestException
435
-	 * @throws OCSException
436
-	 * @throws OCSForbiddenException
437
-	 * @throws OCSNotFoundException
438
-	 * @throws InvalidPathException
439
-	 * @suppress PhanUndeclaredClassMethod
440
-	 */
441
-	public function createShare(
442
-		string $path = null,
443
-		int $permissions = null,
444
-		int $shareType = -1,
445
-		string $shareWith = null,
446
-		string $publicUpload = 'false',
447
-		string $password = '',
448
-		string $sendPasswordByTalk = null,
449
-		string $expireDate = '',
450
-		string $label = ''
451
-	): DataResponse {
452
-		$share = $this->shareManager->newShare();
453
-
454
-		if ($permissions === null) {
455
-			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
456
-		}
457
-
458
-		// Verify path
459
-		if ($path === null) {
460
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
461
-		}
462
-
463
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
464
-		try {
465
-			$path = $userFolder->get($path);
466
-		} catch (NotFoundException $e) {
467
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
468
-		}
469
-
470
-		$share->setNode($path);
471
-
472
-		try {
473
-			$this->lock($share->getNode());
474
-		} catch (LockedException $e) {
475
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
476
-		}
477
-
478
-		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
479
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
480
-		}
481
-
482
-		// Shares always require read permissions
483
-		$permissions |= Constants::PERMISSION_READ;
484
-
485
-		if ($path instanceof \OCP\Files\File) {
486
-			// Single file shares should never have delete or create permissions
487
-			$permissions &= ~Constants::PERMISSION_DELETE;
488
-			$permissions &= ~Constants::PERMISSION_CREATE;
489
-		}
490
-
491
-		/**
492
-		 * Hack for https://github.com/owncloud/core/issues/22587
493
-		 * We check the permissions via webdav. But the permissions of the mount point
494
-		 * do not equal the share permissions. Here we fix that for federated mounts.
495
-		 */
496
-		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
497
-			$permissions &= ~($permissions & ~$path->getPermissions());
498
-		}
499
-
500
-		if ($shareType === IShare::TYPE_USER) {
501
-			// Valid user is required to share
502
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
503
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
504
-			}
505
-			$share->setSharedWith($shareWith);
506
-			$share->setPermissions($permissions);
507
-		} elseif ($shareType === IShare::TYPE_GROUP) {
508
-			if (!$this->shareManager->allowGroupSharing()) {
509
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
510
-			}
511
-
512
-			// Valid group is required to share
513
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
514
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
515
-			}
516
-			$share->setSharedWith($shareWith);
517
-			$share->setPermissions($permissions);
518
-		} elseif ($shareType === IShare::TYPE_LINK
519
-			|| $shareType === IShare::TYPE_EMAIL) {
520
-
521
-			// Can we even share links?
522
-			if (!$this->shareManager->shareApiAllowLinks()) {
523
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
524
-			}
525
-
526
-			if ($publicUpload === 'true') {
527
-				// Check if public upload is allowed
528
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
529
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
530
-				}
531
-
532
-				// Public upload can only be set for folders
533
-				if ($path instanceof \OCP\Files\File) {
534
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
535
-				}
536
-
537
-				$permissions = Constants::PERMISSION_READ |
538
-					Constants::PERMISSION_CREATE |
539
-					Constants::PERMISSION_UPDATE |
540
-					Constants::PERMISSION_DELETE;
541
-			} else {
542
-				$permissions = Constants::PERMISSION_READ;
543
-			}
544
-
545
-			// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
546
-			if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
547
-				$permissions |= Constants::PERMISSION_SHARE;
548
-			}
549
-
550
-			$share->setPermissions($permissions);
551
-
552
-			// Set password
553
-			if ($password !== '') {
554
-				$share->setPassword($password);
555
-			}
556
-
557
-			// Only share by mail have a recipient
558
-			if ($shareType === IShare::TYPE_EMAIL) {
559
-				$share->setSharedWith($shareWith);
560
-			} else {
561
-				// Only link share have a label
562
-				if (!empty($label)) {
563
-					$share->setLabel($label);
564
-				}
565
-			}
566
-
567
-			if ($sendPasswordByTalk === 'true') {
568
-				if (!$this->appManager->isEnabledForUser('spreed')) {
569
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
570
-				}
571
-
572
-				$share->setSendPasswordByTalk(true);
573
-			}
574
-
575
-			//Expire date
576
-			if ($expireDate !== '') {
577
-				try {
578
-					$expireDate = $this->parseDate($expireDate);
579
-					$share->setExpirationDate($expireDate);
580
-				} catch (\Exception $e) {
581
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
582
-				}
583
-			}
584
-		} elseif ($shareType === IShare::TYPE_REMOTE) {
585
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
586
-				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]));
587
-			}
588
-
589
-			$share->setSharedWith($shareWith);
590
-			$share->setPermissions($permissions);
591
-		} elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
592
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
593
-				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]));
594
-			}
595
-
596
-			$share->setSharedWith($shareWith);
597
-			$share->setPermissions($permissions);
598
-		} elseif ($shareType === IShare::TYPE_CIRCLE) {
599
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
600
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
601
-			}
602
-
603
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
604
-
605
-			// Valid circle is required to share
606
-			if ($circle === null) {
607
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
608
-			}
609
-			$share->setSharedWith($shareWith);
610
-			$share->setPermissions($permissions);
611
-		} elseif ($shareType === IShare::TYPE_ROOM) {
612
-			try {
613
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
614
-			} catch (QueryException $e) {
615
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
616
-			}
617
-		} elseif ($shareType === IShare::TYPE_DECK) {
618
-			try {
619
-				$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
620
-			} catch (QueryException $e) {
621
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
622
-			}
623
-		} else {
624
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
625
-		}
626
-
627
-		$share->setShareType($shareType);
628
-		$share->setSharedBy($this->currentUser);
629
-
630
-		try {
631
-			$share = $this->shareManager->createShare($share);
632
-		} catch (GenericShareException $e) {
633
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
634
-			throw new OCSException($e->getHint(), $code);
635
-		} catch (\Exception $e) {
636
-			throw new OCSForbiddenException($e->getMessage(), $e);
637
-		}
638
-
639
-		$output = $this->formatShare($share);
640
-
641
-		return new DataResponse($output);
642
-	}
643
-
644
-	/**
645
-	 * @param null|Node $node
646
-	 * @param boolean $includeTags
647
-	 *
648
-	 * @return array
649
-	 */
650
-	private function getSharedWithMe($node, bool $includeTags): array {
651
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
652
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
653
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
654
-		$roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
655
-		$deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
656
-
657
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
658
-
659
-		$filteredShares = array_filter($shares, function (IShare $share) {
660
-			return $share->getShareOwner() !== $this->currentUser;
661
-		});
662
-
663
-		$formatted = [];
664
-		foreach ($filteredShares as $share) {
665
-			if ($this->canAccessShare($share)) {
666
-				try {
667
-					$formatted[] = $this->formatShare($share);
668
-				} catch (NotFoundException $e) {
669
-					// Ignore this share
670
-				}
671
-			}
672
-		}
673
-
674
-		if ($includeTags) {
675
-			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
676
-		}
677
-
678
-		return $formatted;
679
-	}
680
-
681
-	/**
682
-	 * @param \OCP\Files\Node $folder
683
-	 *
684
-	 * @return array
685
-	 * @throws OCSBadRequestException
686
-	 * @throws NotFoundException
687
-	 */
688
-	private function getSharesInDir(Node $folder): array {
689
-		if (!($folder instanceof \OCP\Files\Folder)) {
690
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
691
-		}
692
-
693
-		$nodes = $folder->getDirectoryListing();
694
-
695
-		/** @var \OCP\Share\IShare[] $shares */
696
-		$shares = array_reduce($nodes, function ($carry, $node) {
697
-			$carry = array_merge($carry, $this->getAllShares($node, true));
698
-			return $carry;
699
-		}, []);
700
-
701
-		// filter out duplicate shares
702
-		$known = [];
703
-
704
-
705
-		$formatted = $miniFormatted = [];
706
-		$resharingRight = false;
707
-		$known = [];
708
-		foreach ($shares as $share) {
709
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
710
-				continue;
711
-			}
712
-
713
-			try {
714
-				$format = $this->formatShare($share);
715
-
716
-				$known[] = $share->getId();
717
-				$formatted[] = $format;
718
-				if ($share->getSharedBy() === $this->currentUser) {
719
-					$miniFormatted[] = $format;
720
-				}
721
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
722
-					$resharingRight = true;
723
-				}
724
-			} catch (\Exception $e) {
725
-				//Ignore this share
726
-			}
727
-		}
728
-
729
-		if (!$resharingRight) {
730
-			$formatted = $miniFormatted;
731
-		}
732
-
733
-		return $formatted;
734
-	}
735
-
736
-	/**
737
-	 * The getShares function.
738
-	 *
739
-	 * @NoAdminRequired
740
-	 *
741
-	 * @param string $shared_with_me
742
-	 * @param string $reshares
743
-	 * @param string $subfiles
744
-	 * @param string $path
745
-	 *
746
-	 * - Get shares by the current user
747
-	 * - Get shares by the current user and reshares (?reshares=true)
748
-	 * - Get shares with the current user (?shared_with_me=true)
749
-	 * - Get shares for a specific path (?path=...)
750
-	 * - Get all shares in a folder (?subfiles=true&path=..)
751
-	 *
752
-	 * @param string $include_tags
753
-	 *
754
-	 * @return DataResponse
755
-	 * @throws NotFoundException
756
-	 * @throws OCSBadRequestException
757
-	 * @throws OCSNotFoundException
758
-	 */
759
-	public function getShares(
760
-		string $shared_with_me = 'false',
761
-		string $reshares = 'false',
762
-		string $subfiles = 'false',
763
-		string $path = '',
764
-		string $include_tags = 'false'
765
-	): DataResponse {
766
-		$node = null;
767
-		if ($path !== '') {
768
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
769
-			try {
770
-				$node = $userFolder->get($path);
771
-				$this->lock($node);
772
-			} catch (NotFoundException $e) {
773
-				throw new OCSNotFoundException(
774
-					$this->l->t('Wrong path, file/folder doesn\'t exist')
775
-				);
776
-			} catch (LockedException $e) {
777
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
778
-			}
779
-		}
780
-
781
-		$shares = $this->getFormattedShares(
782
-			$this->currentUser,
783
-			$node,
784
-			($shared_with_me === 'true'),
785
-			($reshares === 'true'),
786
-			($subfiles === 'true'),
787
-			($include_tags === 'true')
788
-		);
789
-
790
-		return new DataResponse($shares);
791
-	}
792
-
793
-
794
-	/**
795
-	 * @param string $viewer
796
-	 * @param Node $node
797
-	 * @param bool $sharedWithMe
798
-	 * @param bool $reShares
799
-	 * @param bool $subFiles
800
-	 * @param bool $includeTags
801
-	 *
802
-	 * @return array
803
-	 * @throws NotFoundException
804
-	 * @throws OCSBadRequestException
805
-	 */
806
-	private function getFormattedShares(
807
-		string $viewer,
808
-		$node = null,
809
-		bool $sharedWithMe = false,
810
-		bool $reShares = false,
811
-		bool $subFiles = false,
812
-		bool $includeTags = false
813
-	): array {
814
-		if ($sharedWithMe) {
815
-			return $this->getSharedWithMe($node, $includeTags);
816
-		}
817
-
818
-		if ($subFiles) {
819
-			return $this->getSharesInDir($node);
820
-		}
821
-
822
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
823
-
824
-		$known = $formatted = $miniFormatted = [];
825
-		$resharingRight = false;
826
-		foreach ($shares as $share) {
827
-			try {
828
-				$share->getNode();
829
-			} catch (NotFoundException $e) {
830
-				/*
86
+    /** @var IManager */
87
+    private $shareManager;
88
+    /** @var IGroupManager */
89
+    private $groupManager;
90
+    /** @var IUserManager */
91
+    private $userManager;
92
+    /** @var IRootFolder */
93
+    private $rootFolder;
94
+    /** @var IURLGenerator */
95
+    private $urlGenerator;
96
+    /** @var string */
97
+    private $currentUser;
98
+    /** @var IL10N */
99
+    private $l;
100
+    /** @var \OCP\Files\Node */
101
+    private $lockedNode;
102
+    /** @var IConfig */
103
+    private $config;
104
+    /** @var IAppManager */
105
+    private $appManager;
106
+    /** @var IServerContainer */
107
+    private $serverContainer;
108
+    /** @var IUserStatusManager */
109
+    private $userStatusManager;
110
+    /** @var IPreview */
111
+    private $previewManager;
112
+
113
+    /**
114
+     * Share20OCS constructor.
115
+     *
116
+     * @param string $appName
117
+     * @param IRequest $request
118
+     * @param IManager $shareManager
119
+     * @param IGroupManager $groupManager
120
+     * @param IUserManager $userManager
121
+     * @param IRootFolder $rootFolder
122
+     * @param IURLGenerator $urlGenerator
123
+     * @param string $userId
124
+     * @param IL10N $l10n
125
+     * @param IConfig $config
126
+     * @param IAppManager $appManager
127
+     * @param IServerContainer $serverContainer
128
+     * @param IUserStatusManager $userStatusManager
129
+     */
130
+    public function __construct(
131
+        string $appName,
132
+        IRequest $request,
133
+        IManager $shareManager,
134
+        IGroupManager $groupManager,
135
+        IUserManager $userManager,
136
+        IRootFolder $rootFolder,
137
+        IURLGenerator $urlGenerator,
138
+        string $userId = null,
139
+        IL10N $l10n,
140
+        IConfig $config,
141
+        IAppManager $appManager,
142
+        IServerContainer $serverContainer,
143
+        IUserStatusManager $userStatusManager,
144
+        IPreview $previewManager
145
+    ) {
146
+        parent::__construct($appName, $request);
147
+
148
+        $this->shareManager = $shareManager;
149
+        $this->userManager = $userManager;
150
+        $this->groupManager = $groupManager;
151
+        $this->request = $request;
152
+        $this->rootFolder = $rootFolder;
153
+        $this->urlGenerator = $urlGenerator;
154
+        $this->currentUser = $userId;
155
+        $this->l = $l10n;
156
+        $this->config = $config;
157
+        $this->appManager = $appManager;
158
+        $this->serverContainer = $serverContainer;
159
+        $this->userStatusManager = $userStatusManager;
160
+        $this->previewManager = $previewManager;
161
+    }
162
+
163
+    /**
164
+     * Convert an IShare to an array for OCS output
165
+     *
166
+     * @param \OCP\Share\IShare $share
167
+     * @param Node|null $recipientNode
168
+     * @return array
169
+     * @throws NotFoundException In case the node can't be resolved.
170
+     *
171
+     * @suppress PhanUndeclaredClassMethod
172
+     */
173
+    protected function formatShare(IShare $share, Node $recipientNode = null): array {
174
+        $sharedBy = $this->userManager->get($share->getSharedBy());
175
+        $shareOwner = $this->userManager->get($share->getShareOwner());
176
+
177
+        $result = [
178
+            'id' => $share->getId(),
179
+            'share_type' => $share->getShareType(),
180
+            'uid_owner' => $share->getSharedBy(),
181
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
182
+            // recipient permissions
183
+            'permissions' => $share->getPermissions(),
184
+            // current user permissions on this share
185
+            'can_edit' => $this->canEditShare($share),
186
+            'can_delete' => $this->canDeleteShare($share),
187
+            'stime' => $share->getShareTime()->getTimestamp(),
188
+            'parent' => null,
189
+            'expiration' => null,
190
+            'token' => null,
191
+            'uid_file_owner' => $share->getShareOwner(),
192
+            'note' => $share->getNote(),
193
+            'label' => $share->getLabel(),
194
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
195
+        ];
196
+
197
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
198
+        if ($recipientNode) {
199
+            $node = $recipientNode;
200
+        } else {
201
+            $nodes = $userFolder->getById($share->getNodeId());
202
+            if (empty($nodes)) {
203
+                // fallback to guessing the path
204
+                $node = $userFolder->get($share->getTarget());
205
+                if ($node === null || $share->getTarget() === '') {
206
+                    throw new NotFoundException();
207
+                }
208
+            } else {
209
+                $node = reset($nodes);
210
+            }
211
+        }
212
+
213
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
214
+        if ($node instanceof Folder) {
215
+            $result['item_type'] = 'folder';
216
+        } else {
217
+            $result['item_type'] = 'file';
218
+        }
219
+
220
+        $result['mimetype'] = $node->getMimetype();
221
+        $result['has_preview'] = $this->previewManager->isAvailable($node);
222
+        $result['storage_id'] = $node->getStorage()->getId();
223
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
224
+        $result['item_source'] = $node->getId();
225
+        $result['file_source'] = $node->getId();
226
+        $result['file_parent'] = $node->getParent()->getId();
227
+        $result['file_target'] = $share->getTarget();
228
+
229
+        $expiration = $share->getExpirationDate();
230
+        if ($expiration !== null) {
231
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
232
+        }
233
+
234
+        if ($share->getShareType() === IShare::TYPE_USER) {
235
+            $sharedWith = $this->userManager->get($share->getSharedWith());
236
+            $result['share_with'] = $share->getSharedWith();
237
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
238
+            $result['share_with_displayname_unique'] = $sharedWith !== null ? (
239
+                    $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
240
+            ) : $share->getSharedWith();
241
+            $result['status'] = [];
242
+
243
+            $userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
244
+            $userStatus = array_shift($userStatuses);
245
+            if ($userStatus) {
246
+                $result['status'] = [
247
+                    'status' => $userStatus->getStatus(),
248
+                    'message' => $userStatus->getMessage(),
249
+                    'icon' => $userStatus->getIcon(),
250
+                    'clearAt' => $userStatus->getClearAt()
251
+                        ? (int)$userStatus->getClearAt()->format('U')
252
+                        : null,
253
+                ];
254
+            }
255
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
256
+            $group = $this->groupManager->get($share->getSharedWith());
257
+            $result['share_with'] = $share->getSharedWith();
258
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
259
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
260
+
261
+            // "share_with" and "share_with_displayname" for passwords of link
262
+            // shares was deprecated in Nextcloud 15, use "password" instead.
263
+            $result['share_with'] = $share->getPassword();
264
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
265
+
266
+            $result['password'] = $share->getPassword();
267
+
268
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
269
+
270
+            $result['token'] = $share->getToken();
271
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
272
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
273
+            $result['share_with'] = $share->getSharedWith();
274
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
275
+            $result['token'] = $share->getToken();
276
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
277
+            $result['share_with'] = $share->getSharedWith();
278
+            $result['password'] = $share->getPassword();
279
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
280
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
281
+            $result['token'] = $share->getToken();
282
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
283
+            // getSharedWith() returns either "name (type, owner)" or
284
+            // "name (type, owner) [id]", depending on the Circles app version.
285
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
286
+
287
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
288
+            if (empty($result['share_with_displayname'])) {
289
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
290
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
291
+            }
292
+
293
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
294
+
295
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
296
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
297
+            if (is_bool($shareWithLength)) {
298
+                $shareWithLength = -1;
299
+            }
300
+            $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
301
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
302
+            $result['share_with'] = $share->getSharedWith();
303
+            $result['share_with_displayname'] = '';
304
+
305
+            try {
306
+                $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
307
+            } catch (QueryException $e) {
308
+            }
309
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
310
+            $result['share_with'] = $share->getSharedWith();
311
+            $result['share_with_displayname'] = '';
312
+
313
+            try {
314
+                $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
315
+            } catch (QueryException $e) {
316
+            }
317
+        }
318
+
319
+
320
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
321
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
322
+
323
+        return $result;
324
+    }
325
+
326
+    /**
327
+     * Check if one of the users address books knows the exact property, if
328
+     * yes we return the full name.
329
+     *
330
+     * @param string $query
331
+     * @param string $property
332
+     * @return string
333
+     */
334
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
335
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
336
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
337
+        foreach ($result as $r) {
338
+            foreach ($r[$property] as $value) {
339
+                if ($value === $query && $r['FN']) {
340
+                    return $r['FN'];
341
+                }
342
+            }
343
+        }
344
+
345
+        return $query;
346
+    }
347
+
348
+    /**
349
+     * Get a specific share by id
350
+     *
351
+     * @NoAdminRequired
352
+     *
353
+     * @param string $id
354
+     * @return DataResponse
355
+     * @throws OCSNotFoundException
356
+     */
357
+    public function getShare(string $id): DataResponse {
358
+        try {
359
+            $share = $this->getShareById($id);
360
+        } catch (ShareNotFound $e) {
361
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
362
+        }
363
+
364
+        try {
365
+            if ($this->canAccessShare($share)) {
366
+                $share = $this->formatShare($share);
367
+                return new DataResponse([$share]);
368
+            }
369
+        } catch (NotFoundException $e) {
370
+            // Fall trough
371
+        }
372
+
373
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
374
+    }
375
+
376
+    /**
377
+     * Delete a share
378
+     *
379
+     * @NoAdminRequired
380
+     *
381
+     * @param string $id
382
+     * @return DataResponse
383
+     * @throws OCSNotFoundException
384
+     */
385
+    public function deleteShare(string $id): DataResponse {
386
+        try {
387
+            $share = $this->getShareById($id);
388
+        } catch (ShareNotFound $e) {
389
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
390
+        }
391
+
392
+        try {
393
+            $this->lock($share->getNode());
394
+        } catch (LockedException $e) {
395
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
396
+        }
397
+
398
+        if (!$this->canAccessShare($share)) {
399
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
400
+        }
401
+
402
+        // if it's a group share or a room share
403
+        // we don't delete the share, but only the
404
+        // mount point. Allowing it to be restored
405
+        // from the deleted shares
406
+        if ($this->canDeleteShareFromSelf($share)) {
407
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
408
+        } else {
409
+            if (!$this->canDeleteShare($share)) {
410
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
411
+            }
412
+
413
+            $this->shareManager->deleteShare($share);
414
+        }
415
+
416
+        return new DataResponse();
417
+    }
418
+
419
+    /**
420
+     * @NoAdminRequired
421
+     *
422
+     * @param string $path
423
+     * @param int $permissions
424
+     * @param int $shareType
425
+     * @param string $shareWith
426
+     * @param string $publicUpload
427
+     * @param string $password
428
+     * @param string $sendPasswordByTalk
429
+     * @param string $expireDate
430
+     * @param string $label
431
+     *
432
+     * @return DataResponse
433
+     * @throws NotFoundException
434
+     * @throws OCSBadRequestException
435
+     * @throws OCSException
436
+     * @throws OCSForbiddenException
437
+     * @throws OCSNotFoundException
438
+     * @throws InvalidPathException
439
+     * @suppress PhanUndeclaredClassMethod
440
+     */
441
+    public function createShare(
442
+        string $path = null,
443
+        int $permissions = null,
444
+        int $shareType = -1,
445
+        string $shareWith = null,
446
+        string $publicUpload = 'false',
447
+        string $password = '',
448
+        string $sendPasswordByTalk = null,
449
+        string $expireDate = '',
450
+        string $label = ''
451
+    ): DataResponse {
452
+        $share = $this->shareManager->newShare();
453
+
454
+        if ($permissions === null) {
455
+            $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
456
+        }
457
+
458
+        // Verify path
459
+        if ($path === null) {
460
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
461
+        }
462
+
463
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
464
+        try {
465
+            $path = $userFolder->get($path);
466
+        } catch (NotFoundException $e) {
467
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
468
+        }
469
+
470
+        $share->setNode($path);
471
+
472
+        try {
473
+            $this->lock($share->getNode());
474
+        } catch (LockedException $e) {
475
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
476
+        }
477
+
478
+        if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
479
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
480
+        }
481
+
482
+        // Shares always require read permissions
483
+        $permissions |= Constants::PERMISSION_READ;
484
+
485
+        if ($path instanceof \OCP\Files\File) {
486
+            // Single file shares should never have delete or create permissions
487
+            $permissions &= ~Constants::PERMISSION_DELETE;
488
+            $permissions &= ~Constants::PERMISSION_CREATE;
489
+        }
490
+
491
+        /**
492
+         * Hack for https://github.com/owncloud/core/issues/22587
493
+         * We check the permissions via webdav. But the permissions of the mount point
494
+         * do not equal the share permissions. Here we fix that for federated mounts.
495
+         */
496
+        if ($path->getStorage()->instanceOfStorage(Storage::class)) {
497
+            $permissions &= ~($permissions & ~$path->getPermissions());
498
+        }
499
+
500
+        if ($shareType === IShare::TYPE_USER) {
501
+            // Valid user is required to share
502
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
503
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
504
+            }
505
+            $share->setSharedWith($shareWith);
506
+            $share->setPermissions($permissions);
507
+        } elseif ($shareType === IShare::TYPE_GROUP) {
508
+            if (!$this->shareManager->allowGroupSharing()) {
509
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
510
+            }
511
+
512
+            // Valid group is required to share
513
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
514
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
515
+            }
516
+            $share->setSharedWith($shareWith);
517
+            $share->setPermissions($permissions);
518
+        } elseif ($shareType === IShare::TYPE_LINK
519
+            || $shareType === IShare::TYPE_EMAIL) {
520
+
521
+            // Can we even share links?
522
+            if (!$this->shareManager->shareApiAllowLinks()) {
523
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
524
+            }
525
+
526
+            if ($publicUpload === 'true') {
527
+                // Check if public upload is allowed
528
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
529
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
530
+                }
531
+
532
+                // Public upload can only be set for folders
533
+                if ($path instanceof \OCP\Files\File) {
534
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
535
+                }
536
+
537
+                $permissions = Constants::PERMISSION_READ |
538
+                    Constants::PERMISSION_CREATE |
539
+                    Constants::PERMISSION_UPDATE |
540
+                    Constants::PERMISSION_DELETE;
541
+            } else {
542
+                $permissions = Constants::PERMISSION_READ;
543
+            }
544
+
545
+            // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
546
+            if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
547
+                $permissions |= Constants::PERMISSION_SHARE;
548
+            }
549
+
550
+            $share->setPermissions($permissions);
551
+
552
+            // Set password
553
+            if ($password !== '') {
554
+                $share->setPassword($password);
555
+            }
556
+
557
+            // Only share by mail have a recipient
558
+            if ($shareType === IShare::TYPE_EMAIL) {
559
+                $share->setSharedWith($shareWith);
560
+            } else {
561
+                // Only link share have a label
562
+                if (!empty($label)) {
563
+                    $share->setLabel($label);
564
+                }
565
+            }
566
+
567
+            if ($sendPasswordByTalk === 'true') {
568
+                if (!$this->appManager->isEnabledForUser('spreed')) {
569
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
570
+                }
571
+
572
+                $share->setSendPasswordByTalk(true);
573
+            }
574
+
575
+            //Expire date
576
+            if ($expireDate !== '') {
577
+                try {
578
+                    $expireDate = $this->parseDate($expireDate);
579
+                    $share->setExpirationDate($expireDate);
580
+                } catch (\Exception $e) {
581
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
582
+                }
583
+            }
584
+        } elseif ($shareType === IShare::TYPE_REMOTE) {
585
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
586
+                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]));
587
+            }
588
+
589
+            $share->setSharedWith($shareWith);
590
+            $share->setPermissions($permissions);
591
+        } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
592
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
593
+                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]));
594
+            }
595
+
596
+            $share->setSharedWith($shareWith);
597
+            $share->setPermissions($permissions);
598
+        } elseif ($shareType === IShare::TYPE_CIRCLE) {
599
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
600
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
601
+            }
602
+
603
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
604
+
605
+            // Valid circle is required to share
606
+            if ($circle === null) {
607
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
608
+            }
609
+            $share->setSharedWith($shareWith);
610
+            $share->setPermissions($permissions);
611
+        } elseif ($shareType === IShare::TYPE_ROOM) {
612
+            try {
613
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
614
+            } catch (QueryException $e) {
615
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
616
+            }
617
+        } elseif ($shareType === IShare::TYPE_DECK) {
618
+            try {
619
+                $this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
620
+            } catch (QueryException $e) {
621
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
622
+            }
623
+        } else {
624
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
625
+        }
626
+
627
+        $share->setShareType($shareType);
628
+        $share->setSharedBy($this->currentUser);
629
+
630
+        try {
631
+            $share = $this->shareManager->createShare($share);
632
+        } catch (GenericShareException $e) {
633
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
634
+            throw new OCSException($e->getHint(), $code);
635
+        } catch (\Exception $e) {
636
+            throw new OCSForbiddenException($e->getMessage(), $e);
637
+        }
638
+
639
+        $output = $this->formatShare($share);
640
+
641
+        return new DataResponse($output);
642
+    }
643
+
644
+    /**
645
+     * @param null|Node $node
646
+     * @param boolean $includeTags
647
+     *
648
+     * @return array
649
+     */
650
+    private function getSharedWithMe($node, bool $includeTags): array {
651
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
652
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
653
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
654
+        $roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
655
+        $deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
656
+
657
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
658
+
659
+        $filteredShares = array_filter($shares, function (IShare $share) {
660
+            return $share->getShareOwner() !== $this->currentUser;
661
+        });
662
+
663
+        $formatted = [];
664
+        foreach ($filteredShares as $share) {
665
+            if ($this->canAccessShare($share)) {
666
+                try {
667
+                    $formatted[] = $this->formatShare($share);
668
+                } catch (NotFoundException $e) {
669
+                    // Ignore this share
670
+                }
671
+            }
672
+        }
673
+
674
+        if ($includeTags) {
675
+            $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
676
+        }
677
+
678
+        return $formatted;
679
+    }
680
+
681
+    /**
682
+     * @param \OCP\Files\Node $folder
683
+     *
684
+     * @return array
685
+     * @throws OCSBadRequestException
686
+     * @throws NotFoundException
687
+     */
688
+    private function getSharesInDir(Node $folder): array {
689
+        if (!($folder instanceof \OCP\Files\Folder)) {
690
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
691
+        }
692
+
693
+        $nodes = $folder->getDirectoryListing();
694
+
695
+        /** @var \OCP\Share\IShare[] $shares */
696
+        $shares = array_reduce($nodes, function ($carry, $node) {
697
+            $carry = array_merge($carry, $this->getAllShares($node, true));
698
+            return $carry;
699
+        }, []);
700
+
701
+        // filter out duplicate shares
702
+        $known = [];
703
+
704
+
705
+        $formatted = $miniFormatted = [];
706
+        $resharingRight = false;
707
+        $known = [];
708
+        foreach ($shares as $share) {
709
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
710
+                continue;
711
+            }
712
+
713
+            try {
714
+                $format = $this->formatShare($share);
715
+
716
+                $known[] = $share->getId();
717
+                $formatted[] = $format;
718
+                if ($share->getSharedBy() === $this->currentUser) {
719
+                    $miniFormatted[] = $format;
720
+                }
721
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
722
+                    $resharingRight = true;
723
+                }
724
+            } catch (\Exception $e) {
725
+                //Ignore this share
726
+            }
727
+        }
728
+
729
+        if (!$resharingRight) {
730
+            $formatted = $miniFormatted;
731
+        }
732
+
733
+        return $formatted;
734
+    }
735
+
736
+    /**
737
+     * The getShares function.
738
+     *
739
+     * @NoAdminRequired
740
+     *
741
+     * @param string $shared_with_me
742
+     * @param string $reshares
743
+     * @param string $subfiles
744
+     * @param string $path
745
+     *
746
+     * - Get shares by the current user
747
+     * - Get shares by the current user and reshares (?reshares=true)
748
+     * - Get shares with the current user (?shared_with_me=true)
749
+     * - Get shares for a specific path (?path=...)
750
+     * - Get all shares in a folder (?subfiles=true&path=..)
751
+     *
752
+     * @param string $include_tags
753
+     *
754
+     * @return DataResponse
755
+     * @throws NotFoundException
756
+     * @throws OCSBadRequestException
757
+     * @throws OCSNotFoundException
758
+     */
759
+    public function getShares(
760
+        string $shared_with_me = 'false',
761
+        string $reshares = 'false',
762
+        string $subfiles = 'false',
763
+        string $path = '',
764
+        string $include_tags = 'false'
765
+    ): DataResponse {
766
+        $node = null;
767
+        if ($path !== '') {
768
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
769
+            try {
770
+                $node = $userFolder->get($path);
771
+                $this->lock($node);
772
+            } catch (NotFoundException $e) {
773
+                throw new OCSNotFoundException(
774
+                    $this->l->t('Wrong path, file/folder doesn\'t exist')
775
+                );
776
+            } catch (LockedException $e) {
777
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
778
+            }
779
+        }
780
+
781
+        $shares = $this->getFormattedShares(
782
+            $this->currentUser,
783
+            $node,
784
+            ($shared_with_me === 'true'),
785
+            ($reshares === 'true'),
786
+            ($subfiles === 'true'),
787
+            ($include_tags === 'true')
788
+        );
789
+
790
+        return new DataResponse($shares);
791
+    }
792
+
793
+
794
+    /**
795
+     * @param string $viewer
796
+     * @param Node $node
797
+     * @param bool $sharedWithMe
798
+     * @param bool $reShares
799
+     * @param bool $subFiles
800
+     * @param bool $includeTags
801
+     *
802
+     * @return array
803
+     * @throws NotFoundException
804
+     * @throws OCSBadRequestException
805
+     */
806
+    private function getFormattedShares(
807
+        string $viewer,
808
+        $node = null,
809
+        bool $sharedWithMe = false,
810
+        bool $reShares = false,
811
+        bool $subFiles = false,
812
+        bool $includeTags = false
813
+    ): array {
814
+        if ($sharedWithMe) {
815
+            return $this->getSharedWithMe($node, $includeTags);
816
+        }
817
+
818
+        if ($subFiles) {
819
+            return $this->getSharesInDir($node);
820
+        }
821
+
822
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
823
+
824
+        $known = $formatted = $miniFormatted = [];
825
+        $resharingRight = false;
826
+        foreach ($shares as $share) {
827
+            try {
828
+                $share->getNode();
829
+            } catch (NotFoundException $e) {
830
+                /*
831 831
 				 * Ignore shares where we can't get the node
832 832
 				 * For example deleted shares
833 833
 				 */
834
-				continue;
835
-			}
836
-
837
-			if (in_array($share->getId(), $known)
838
-				|| ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
839
-				continue;
840
-			}
841
-
842
-			$known[] = $share->getId();
843
-			try {
844
-				/** @var IShare $share */
845
-				$format = $this->formatShare($share, $node);
846
-				$formatted[] = $format;
847
-
848
-				// let's also build a list of shares created
849
-				// by the current user only, in case
850
-				// there is no resharing rights
851
-				if ($share->getSharedBy() === $this->currentUser) {
852
-					$miniFormatted[] = $format;
853
-				}
854
-
855
-				// check if one of those share is shared with me
856
-				// and if I have resharing rights on it
857
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
858
-					$resharingRight = true;
859
-				}
860
-			} catch (InvalidPathException | NotFoundException $e) {
861
-			}
862
-		}
863
-
864
-		if (!$resharingRight) {
865
-			$formatted = $miniFormatted;
866
-		}
867
-
868
-		if ($includeTags) {
869
-			$formatted =
870
-				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
871
-		}
872
-
873
-		return $formatted;
874
-	}
875
-
876
-
877
-	/**
878
-	 * The getInheritedShares function.
879
-	 * returns all shares relative to a file, including parent folders shares rights.
880
-	 *
881
-	 * @NoAdminRequired
882
-	 *
883
-	 * @param string $path
884
-	 *
885
-	 * - Get shares by the current user
886
-	 * - Get shares by the current user and reshares (?reshares=true)
887
-	 * - Get shares with the current user (?shared_with_me=true)
888
-	 * - Get shares for a specific path (?path=...)
889
-	 * - Get all shares in a folder (?subfiles=true&path=..)
890
-	 *
891
-	 * @return DataResponse
892
-	 * @throws InvalidPathException
893
-	 * @throws NotFoundException
894
-	 * @throws OCSNotFoundException
895
-	 * @throws OCSBadRequestException
896
-	 * @throws SharingRightsException
897
-	 */
898
-	public function getInheritedShares(string $path): DataResponse {
899
-
900
-		// get Node from (string) path.
901
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
902
-		try {
903
-			$node = $userFolder->get($path);
904
-			$this->lock($node);
905
-		} catch (\OCP\Files\NotFoundException $e) {
906
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
907
-		} catch (LockedException $e) {
908
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
909
-		}
910
-
911
-		if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
912
-			throw new SharingRightsException('no sharing rights on this item');
913
-		}
914
-
915
-		// The current top parent we have access to
916
-		$parent = $node;
917
-
918
-		// initiate real owner.
919
-		$owner = $node->getOwner()
920
-					  ->getUID();
921
-		if (!$this->userManager->userExists($owner)) {
922
-			return new DataResponse([]);
923
-		}
924
-
925
-		// get node based on the owner, fix owner in case of external storage
926
-		$userFolder = $this->rootFolder->getUserFolder($owner);
927
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
928
-			$owner = $node->getOwner()
929
-						  ->getUID();
930
-			$userFolder = $this->rootFolder->getUserFolder($owner);
931
-			$nodes = $userFolder->getById($node->getId());
932
-			$node = array_shift($nodes);
933
-		}
934
-		$basePath = $userFolder->getPath();
935
-
936
-		// generate node list for each parent folders
937
-		/** @var Node[] $nodes */
938
-		$nodes = [];
939
-		while ($node->getPath() !== $basePath) {
940
-			$node = $node->getParent();
941
-			$nodes[] = $node;
942
-		}
943
-
944
-		// The user that is requesting this list
945
-		$currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
946
-
947
-		// for each nodes, retrieve shares.
948
-		$shares = [];
949
-
950
-		foreach ($nodes as $node) {
951
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
952
-
953
-			$currentUserNodes = $currentUserFolder->getById($node->getId());
954
-			if (!empty($currentUserNodes)) {
955
-				$parent = array_pop($currentUserNodes);
956
-			}
957
-
958
-			$subPath = $currentUserFolder->getRelativePath($parent->getPath());
959
-			foreach ($getShares as &$share) {
960
-				$share['via_fileid'] = $parent->getId();
961
-				$share['via_path'] = $subPath;
962
-			}
963
-			$this->mergeFormattedShares($shares, $getShares);
964
-		}
965
-
966
-		return new DataResponse(array_values($shares));
967
-	}
968
-
969
-
970
-	/**
971
-	 * @NoAdminRequired
972
-	 *
973
-	 * @param string $id
974
-	 * @param int $permissions
975
-	 * @param string $password
976
-	 * @param string $sendPasswordByTalk
977
-	 * @param string $publicUpload
978
-	 * @param string $expireDate
979
-	 * @param string $note
980
-	 * @param string $label
981
-	 * @param string $hideDownload
982
-	 * @return DataResponse
983
-	 * @throws LockedException
984
-	 * @throws NotFoundException
985
-	 * @throws OCSBadRequestException
986
-	 * @throws OCSForbiddenException
987
-	 * @throws OCSNotFoundException
988
-	 */
989
-	public function updateShare(
990
-		string $id,
991
-		int $permissions = null,
992
-		string $password = null,
993
-		string $sendPasswordByTalk = null,
994
-		string $publicUpload = null,
995
-		string $expireDate = null,
996
-		string $note = null,
997
-		string $label = null,
998
-		string $hideDownload = null
999
-	): DataResponse {
1000
-		try {
1001
-			$share = $this->getShareById($id);
1002
-		} catch (ShareNotFound $e) {
1003
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1004
-		}
1005
-
1006
-		$this->lock($share->getNode());
1007
-
1008
-		if (!$this->canAccessShare($share, false)) {
1009
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1010
-		}
1011
-
1012
-		if (!$this->canEditShare($share)) {
1013
-			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1014
-		}
1015
-
1016
-		if (
1017
-			$permissions === null &&
1018
-			$password === null &&
1019
-			$sendPasswordByTalk === null &&
1020
-			$publicUpload === null &&
1021
-			$expireDate === null &&
1022
-			$note === null &&
1023
-			$label === null &&
1024
-			$hideDownload === null
1025
-		) {
1026
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1027
-		}
1028
-
1029
-		if ($note !== null) {
1030
-			$share->setNote($note);
1031
-		}
1032
-
1033
-		/**
1034
-		 * expirationdate, password and publicUpload only make sense for link shares
1035
-		 */
1036
-		if ($share->getShareType() === IShare::TYPE_LINK
1037
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1038
-
1039
-			/**
1040
-			 * We do not allow editing link shares that the current user
1041
-			 * doesn't own. This is confusing and lead to errors when
1042
-			 * someone else edit a password or expiration date without
1043
-			 * the share owner knowing about it.
1044
-			 * We only allow deletion
1045
-			 */
1046
-
1047
-			if ($share->getSharedBy() !== $this->currentUser) {
1048
-				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1049
-			}
1050
-
1051
-			// Update hide download state
1052
-			if ($hideDownload === 'true') {
1053
-				$share->setHideDownload(true);
1054
-			} elseif ($hideDownload === 'false') {
1055
-				$share->setHideDownload(false);
1056
-			}
1057
-
1058
-			$newPermissions = null;
1059
-			if ($publicUpload === 'true') {
1060
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1061
-			} elseif ($publicUpload === 'false') {
1062
-				$newPermissions = Constants::PERMISSION_READ;
1063
-			}
1064
-
1065
-			if ($permissions !== null) {
1066
-				$newPermissions = (int) $permissions;
1067
-				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1068
-			}
1069
-
1070
-			if ($newPermissions !== null &&
1071
-				!in_array($newPermissions, [
1072
-					Constants::PERMISSION_READ,
1073
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1074
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1075
-					Constants::PERMISSION_CREATE, // hidden file list
1076
-					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1077
-				], true)
1078
-			) {
1079
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1080
-			}
1081
-
1082
-			if (
1083
-				// legacy
1084
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1085
-				// correct
1086
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1087
-			) {
1088
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1089
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1090
-				}
1091
-
1092
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1093
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1094
-				}
1095
-
1096
-				// normalize to correct public upload permissions
1097
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1098
-			}
1099
-
1100
-			if ($newPermissions !== null) {
1101
-				// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1102
-				if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1103
-					$newPermissions |= Constants::PERMISSION_SHARE;
1104
-				}
1105
-
1106
-				$share->setPermissions($newPermissions);
1107
-				$permissions = $newPermissions;
1108
-			}
1109
-
1110
-			if ($expireDate === '') {
1111
-				$share->setExpirationDate(null);
1112
-			} elseif ($expireDate !== null) {
1113
-				try {
1114
-					$expireDate = $this->parseDate($expireDate);
1115
-				} catch (\Exception $e) {
1116
-					throw new OCSBadRequestException($e->getMessage(), $e);
1117
-				}
1118
-				$share->setExpirationDate($expireDate);
1119
-			}
1120
-
1121
-			if ($password === '') {
1122
-				$share->setPassword(null);
1123
-			} elseif ($password !== null) {
1124
-				$share->setPassword($password);
1125
-			}
1126
-
1127
-			// only link shares have labels
1128
-			if ($share->getShareType() === IShare::TYPE_LINK && $label !== null) {
1129
-				if (strlen($label) > 255) {
1130
-					throw new OCSBadRequestException("Maxmimum label length is 255");
1131
-				}
1132
-				$share->setLabel($label);
1133
-			}
1134
-
1135
-			if ($sendPasswordByTalk === 'true') {
1136
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1137
-					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1138
-				}
1139
-
1140
-				$share->setSendPasswordByTalk(true);
1141
-			} elseif ($sendPasswordByTalk !== null) {
1142
-				$share->setSendPasswordByTalk(false);
1143
-			}
1144
-		}
1145
-
1146
-		// NOT A LINK SHARE
1147
-		else {
1148
-			if ($permissions !== null) {
1149
-				$permissions = (int) $permissions;
1150
-				$share->setPermissions($permissions);
1151
-			}
1152
-
1153
-			if ($expireDate === '') {
1154
-				$share->setExpirationDate(null);
1155
-			} elseif ($expireDate !== null) {
1156
-				try {
1157
-					$expireDate = $this->parseDate($expireDate);
1158
-				} catch (\Exception $e) {
1159
-					throw new OCSBadRequestException($e->getMessage(), $e);
1160
-				}
1161
-				$share->setExpirationDate($expireDate);
1162
-			}
1163
-		}
1164
-
1165
-		try {
1166
-			$share = $this->shareManager->updateShare($share);
1167
-		} catch (GenericShareException $e) {
1168
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1169
-			throw new OCSException($e->getHint(), $code);
1170
-		} catch (\Exception $e) {
1171
-			throw new OCSBadRequestException($e->getMessage(), $e);
1172
-		}
1173
-
1174
-		return new DataResponse($this->formatShare($share));
1175
-	}
1176
-
1177
-	/**
1178
-	 * @NoAdminRequired
1179
-	 */
1180
-	public function pendingShares(): DataResponse {
1181
-		$pendingShares = [];
1182
-
1183
-		$shareTypes = [
1184
-			IShare::TYPE_USER,
1185
-			IShare::TYPE_GROUP
1186
-		];
1187
-
1188
-		foreach ($shareTypes as $shareType) {
1189
-			$shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1190
-
1191
-			foreach ($shares as $share) {
1192
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1193
-					$pendingShares[] = $share;
1194
-				}
1195
-			}
1196
-		}
1197
-
1198
-		$result = array_filter(array_map(function (IShare $share) {
1199
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1200
-			$nodes = $userFolder->getById($share->getNodeId());
1201
-			if (empty($nodes)) {
1202
-				// fallback to guessing the path
1203
-				$node = $userFolder->get($share->getTarget());
1204
-				if ($node === null || $share->getTarget() === '') {
1205
-					return null;
1206
-				}
1207
-			} else {
1208
-				$node = $nodes[0];
1209
-			}
1210
-
1211
-			try {
1212
-				$formattedShare = $this->formatShare($share, $node);
1213
-				$formattedShare['status'] = $share->getStatus();
1214
-				$formattedShare['path'] = $share->getNode()->getName();
1215
-				$formattedShare['permissions'] = 0;
1216
-				return $formattedShare;
1217
-			} catch (NotFoundException $e) {
1218
-				return null;
1219
-			}
1220
-		}, $pendingShares), function ($entry) {
1221
-			return $entry !== null;
1222
-		});
1223
-
1224
-		return new DataResponse($result);
1225
-	}
1226
-
1227
-	/**
1228
-	 * @NoAdminRequired
1229
-	 *
1230
-	 * @param string $id
1231
-	 * @return DataResponse
1232
-	 * @throws OCSNotFoundException
1233
-	 * @throws OCSException
1234
-	 * @throws OCSBadRequestException
1235
-	 */
1236
-	public function acceptShare(string $id): DataResponse {
1237
-		try {
1238
-			$share = $this->getShareById($id);
1239
-		} catch (ShareNotFound $e) {
1240
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1241
-		}
1242
-
1243
-		if (!$this->canAccessShare($share)) {
1244
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1245
-		}
1246
-
1247
-		try {
1248
-			$this->shareManager->acceptShare($share, $this->currentUser);
1249
-		} catch (GenericShareException $e) {
1250
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1251
-			throw new OCSException($e->getHint(), $code);
1252
-		} catch (\Exception $e) {
1253
-			throw new OCSBadRequestException($e->getMessage(), $e);
1254
-		}
1255
-
1256
-		return new DataResponse();
1257
-	}
1258
-
1259
-	/**
1260
-	 * Does the user have read permission on the share
1261
-	 *
1262
-	 * @param \OCP\Share\IShare $share the share to check
1263
-	 * @param boolean $checkGroups check groups as well?
1264
-	 * @return boolean
1265
-	 * @throws NotFoundException
1266
-	 *
1267
-	 * @suppress PhanUndeclaredClassMethod
1268
-	 */
1269
-	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1270
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1271
-		if ($share->getPermissions() === 0) {
1272
-			return false;
1273
-		}
1274
-
1275
-		// Owner of the file and the sharer of the file can always get share
1276
-		if ($share->getShareOwner() === $this->currentUser
1277
-			|| $share->getSharedBy() === $this->currentUser) {
1278
-			return true;
1279
-		}
1280
-
1281
-		// If the share is shared with you, you can access it!
1282
-		if ($share->getShareType() === IShare::TYPE_USER
1283
-			&& $share->getSharedWith() === $this->currentUser) {
1284
-			return true;
1285
-		}
1286
-
1287
-		// Have reshare rights on the shared file/folder ?
1288
-		// Does the currentUser have access to the shared file?
1289
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1290
-		$files = $userFolder->getById($share->getNodeId());
1291
-		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1292
-			return true;
1293
-		}
1294
-
1295
-		// If in the recipient group, you can see the share
1296
-		if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1297
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1298
-			$user = $this->userManager->get($this->currentUser);
1299
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1300
-				return true;
1301
-			}
1302
-		}
1303
-
1304
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1305
-			// TODO: have a sanity check like above?
1306
-			return true;
1307
-		}
1308
-
1309
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1310
-			try {
1311
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1312
-			} catch (QueryException $e) {
1313
-				return false;
1314
-			}
1315
-		}
1316
-
1317
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1318
-			try {
1319
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1320
-			} catch (QueryException $e) {
1321
-				return false;
1322
-			}
1323
-		}
1324
-
1325
-		return false;
1326
-	}
1327
-
1328
-	/**
1329
-	 * Does the user have edit permission on the share
1330
-	 *
1331
-	 * @param \OCP\Share\IShare $share the share to check
1332
-	 * @return boolean
1333
-	 */
1334
-	protected function canEditShare(\OCP\Share\IShare $share): bool {
1335
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1336
-		if ($share->getPermissions() === 0) {
1337
-			return false;
1338
-		}
1339
-
1340
-		// The owner of the file and the creator of the share
1341
-		// can always edit the share
1342
-		if ($share->getShareOwner() === $this->currentUser ||
1343
-			$share->getSharedBy() === $this->currentUser
1344
-		) {
1345
-			return true;
1346
-		}
1347
-
1348
-		//! we do NOT support some kind of `admin` in groups.
1349
-		//! You cannot edit shares shared to a group you're
1350
-		//! a member of if you're not the share owner or the file owner!
1351
-
1352
-		return false;
1353
-	}
1354
-
1355
-	/**
1356
-	 * Does the user have delete permission on the share
1357
-	 *
1358
-	 * @param \OCP\Share\IShare $share the share to check
1359
-	 * @return boolean
1360
-	 */
1361
-	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1362
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1363
-		if ($share->getPermissions() === 0) {
1364
-			return false;
1365
-		}
1366
-
1367
-		// if the user is the recipient, i can unshare
1368
-		// the share with self
1369
-		if ($share->getShareType() === IShare::TYPE_USER &&
1370
-			$share->getSharedWith() === $this->currentUser
1371
-		) {
1372
-			return true;
1373
-		}
1374
-
1375
-		// The owner of the file and the creator of the share
1376
-		// can always delete the share
1377
-		if ($share->getShareOwner() === $this->currentUser ||
1378
-			$share->getSharedBy() === $this->currentUser
1379
-		) {
1380
-			return true;
1381
-		}
1382
-
1383
-		return false;
1384
-	}
1385
-
1386
-	/**
1387
-	 * Does the user have delete permission on the share
1388
-	 * This differs from the canDeleteShare function as it only
1389
-	 * remove the share for the current user. It does NOT
1390
-	 * completely delete the share but only the mount point.
1391
-	 * It can then be restored from the deleted shares section.
1392
-	 *
1393
-	 * @param \OCP\Share\IShare $share the share to check
1394
-	 * @return boolean
1395
-	 *
1396
-	 * @suppress PhanUndeclaredClassMethod
1397
-	 */
1398
-	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1399
-		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1400
-			$share->getShareType() !== IShare::TYPE_ROOM &&
1401
-			$share->getShareType() !== IShare::TYPE_DECK
1402
-		) {
1403
-			return false;
1404
-		}
1405
-
1406
-		if ($share->getShareOwner() === $this->currentUser ||
1407
-			$share->getSharedBy() === $this->currentUser
1408
-		) {
1409
-			// Delete the whole share, not just for self
1410
-			return false;
1411
-		}
1412
-
1413
-		// If in the recipient group, you can delete the share from self
1414
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1415
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1416
-			$user = $this->userManager->get($this->currentUser);
1417
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1418
-				return true;
1419
-			}
1420
-		}
1421
-
1422
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1423
-			try {
1424
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1425
-			} catch (QueryException $e) {
1426
-				return false;
1427
-			}
1428
-		}
1429
-
1430
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1431
-			try {
1432
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1433
-			} catch (QueryException $e) {
1434
-				return false;
1435
-			}
1436
-		}
1437
-
1438
-		return false;
1439
-	}
1440
-
1441
-	/**
1442
-	 * Make sure that the passed date is valid ISO 8601
1443
-	 * So YYYY-MM-DD
1444
-	 * If not throw an exception
1445
-	 *
1446
-	 * @param string $expireDate
1447
-	 *
1448
-	 * @throws \Exception
1449
-	 * @return \DateTime
1450
-	 */
1451
-	private function parseDate(string $expireDate): \DateTime {
1452
-		try {
1453
-			$date = new \DateTime($expireDate);
1454
-		} catch (\Exception $e) {
1455
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1456
-		}
1457
-
1458
-		if ($date === false) {
1459
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1460
-		}
1461
-
1462
-		$date->setTime(0, 0, 0);
1463
-
1464
-		return $date;
1465
-	}
1466
-
1467
-	/**
1468
-	 * Since we have multiple providers but the OCS Share API v1 does
1469
-	 * not support this we need to check all backends.
1470
-	 *
1471
-	 * @param string $id
1472
-	 * @return \OCP\Share\IShare
1473
-	 * @throws ShareNotFound
1474
-	 */
1475
-	private function getShareById(string $id): IShare {
1476
-		$share = null;
1477
-
1478
-		// First check if it is an internal share.
1479
-		try {
1480
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1481
-			return $share;
1482
-		} catch (ShareNotFound $e) {
1483
-			// Do nothing, just try the other share type
1484
-		}
1485
-
1486
-
1487
-		try {
1488
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1489
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1490
-				return $share;
1491
-			}
1492
-		} catch (ShareNotFound $e) {
1493
-			// Do nothing, just try the other share type
1494
-		}
1495
-
1496
-		try {
1497
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1498
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1499
-				return $share;
1500
-			}
1501
-		} catch (ShareNotFound $e) {
1502
-			// Do nothing, just try the other share type
1503
-		}
1504
-
1505
-		try {
1506
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1507
-			return $share;
1508
-		} catch (ShareNotFound $e) {
1509
-			// Do nothing, just try the other share type
1510
-		}
1511
-
1512
-		try {
1513
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1514
-				$share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1515
-				return $share;
1516
-			}
1517
-		} catch (ShareNotFound $e) {
1518
-			// Do nothing, just try the other share type
1519
-		}
1520
-
1521
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1522
-			throw new ShareNotFound();
1523
-		}
1524
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1525
-
1526
-		return $share;
1527
-	}
1528
-
1529
-	/**
1530
-	 * Lock a Node
1531
-	 *
1532
-	 * @param \OCP\Files\Node $node
1533
-	 * @throws LockedException
1534
-	 */
1535
-	private function lock(\OCP\Files\Node $node) {
1536
-		$node->lock(ILockingProvider::LOCK_SHARED);
1537
-		$this->lockedNode = $node;
1538
-	}
1539
-
1540
-	/**
1541
-	 * Cleanup the remaining locks
1542
-	 * @throws LockedException
1543
-	 */
1544
-	public function cleanup() {
1545
-		if ($this->lockedNode !== null) {
1546
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1547
-		}
1548
-	}
1549
-
1550
-	/**
1551
-	 * Returns the helper of ShareAPIController for room shares.
1552
-	 *
1553
-	 * If the Talk application is not enabled or the helper is not available
1554
-	 * a QueryException is thrown instead.
1555
-	 *
1556
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1557
-	 * @throws QueryException
1558
-	 */
1559
-	private function getRoomShareHelper() {
1560
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1561
-			throw new QueryException();
1562
-		}
1563
-
1564
-		return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1565
-	}
1566
-
1567
-	/**
1568
-	 * Returns the helper of ShareAPIHelper for deck shares.
1569
-	 *
1570
-	 * If the Deck application is not enabled or the helper is not available
1571
-	 * a QueryException is thrown instead.
1572
-	 *
1573
-	 * @return \OCA\Deck\Sharing\ShareAPIHelper
1574
-	 * @throws QueryException
1575
-	 */
1576
-	private function getDeckShareHelper() {
1577
-		if (!$this->appManager->isEnabledForUser('deck')) {
1578
-			throw new QueryException();
1579
-		}
1580
-
1581
-		return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1582
-	}
1583
-
1584
-	/**
1585
-	 * @param string $viewer
1586
-	 * @param Node $node
1587
-	 * @param bool $reShares
1588
-	 *
1589
-	 * @return IShare[]
1590
-	 */
1591
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1592
-		$providers = [
1593
-			IShare::TYPE_USER,
1594
-			IShare::TYPE_GROUP,
1595
-			IShare::TYPE_LINK,
1596
-			IShare::TYPE_EMAIL,
1597
-			IShare::TYPE_EMAIL,
1598
-			IShare::TYPE_CIRCLE,
1599
-			IShare::TYPE_ROOM,
1600
-			IShare::TYPE_DECK
1601
-		];
1602
-
1603
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1604
-		$shares = [];
1605
-		foreach ($providers as $provider) {
1606
-			if (!$this->shareManager->shareProviderExists($provider)) {
1607
-				continue;
1608
-			}
1609
-
1610
-			$providerShares =
1611
-				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1612
-			$shares = array_merge($shares, $providerShares);
1613
-		}
1614
-
1615
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1616
-			$federatedShares = $this->shareManager->getSharesBy(
1617
-				$this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1618
-			);
1619
-			$shares = array_merge($shares, $federatedShares);
1620
-		}
1621
-
1622
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1623
-			$federatedShares = $this->shareManager->getSharesBy(
1624
-				$this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1625
-			);
1626
-			$shares = array_merge($shares, $federatedShares);
1627
-		}
1628
-
1629
-		return $shares;
1630
-	}
1631
-
1632
-
1633
-	/**
1634
-	 * @param Node $node
1635
-	 *
1636
-	 * @throws SharingRightsException
1637
-	 */
1638
-	private function confirmSharingRights(Node $node): void {
1639
-		if (!$this->hasResharingRights($this->currentUser, $node)) {
1640
-			throw new SharingRightsException('no sharing rights on this item');
1641
-		}
1642
-	}
1643
-
1644
-
1645
-	/**
1646
-	 * @param string $viewer
1647
-	 * @param Node $node
1648
-	 *
1649
-	 * @return bool
1650
-	 */
1651
-	private function hasResharingRights($viewer, $node): bool {
1652
-		if ($viewer === $node->getOwner()->getUID()) {
1653
-			return true;
1654
-		}
1655
-
1656
-		foreach ([$node, $node->getParent()] as $node) {
1657
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1658
-			foreach ($shares as $share) {
1659
-				try {
1660
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1661
-						return true;
1662
-					}
1663
-				} catch (InvalidPathException | NotFoundException $e) {
1664
-				}
1665
-			}
1666
-		}
1667
-
1668
-		return false;
1669
-	}
1670
-
1671
-
1672
-	/**
1673
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1674
-	 *
1675
-	 * @suppress PhanUndeclaredClassMethod
1676
-	 *
1677
-	 * @param string $userId
1678
-	 * @param IShare $share
1679
-	 * @param Node $node
1680
-	 *
1681
-	 * @return bool
1682
-	 * @throws NotFoundException
1683
-	 * @throws InvalidPathException
1684
-	 */
1685
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1686
-		if ($share->getShareOwner() === $userId) {
1687
-			return true;
1688
-		}
1689
-
1690
-		// we check that current user have parent resharing rights on the current file
1691
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1692
-			return true;
1693
-		}
1694
-
1695
-		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1696
-			return false;
1697
-		}
1698
-
1699
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1700
-			return true;
1701
-		}
1702
-
1703
-		if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1704
-			return true;
1705
-		}
1706
-
1707
-		if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1708
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1709
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1710
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1711
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1712
-			if ($shareWithLength === false) {
1713
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart);
1714
-			} else {
1715
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1716
-			}
1717
-			try {
1718
-				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1719
-				if ($member->getLevel() >= 4) {
1720
-					return true;
1721
-				}
1722
-				return false;
1723
-			} catch (QueryException $e) {
1724
-				return false;
1725
-			}
1726
-		}
1727
-
1728
-		return false;
1729
-	}
1730
-
1731
-	/**
1732
-	 * Get all the shares for the current user
1733
-	 *
1734
-	 * @param Node|null $path
1735
-	 * @param boolean $reshares
1736
-	 * @return IShare[]
1737
-	 */
1738
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
1739
-		// Get all shares
1740
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1741
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1742
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1743
-
1744
-		// EMAIL SHARES
1745
-		$mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1746
-
1747
-		// CIRCLE SHARES
1748
-		$circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1749
-
1750
-		// TALK SHARES
1751
-		$roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1752
-
1753
-		$deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1754
-
1755
-		// FEDERATION
1756
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1757
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1758
-		} else {
1759
-			$federatedShares = [];
1760
-		}
1761
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1762
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1763
-		} else {
1764
-			$federatedGroupShares = [];
1765
-		}
1766
-
1767
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1768
-	}
1769
-
1770
-
1771
-	/**
1772
-	 * merging already formatted shares.
1773
-	 * We'll make an associative array to easily detect duplicate Ids.
1774
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1775
-	 *
1776
-	 * @param array $shares
1777
-	 * @param array $newShares
1778
-	 */
1779
-	private function mergeFormattedShares(array &$shares, array $newShares) {
1780
-		foreach ($newShares as $newShare) {
1781
-			if (!array_key_exists($newShare['id'], $shares)) {
1782
-				$shares[$newShare['id']] = $newShare;
1783
-			}
1784
-		}
1785
-	}
834
+                continue;
835
+            }
836
+
837
+            if (in_array($share->getId(), $known)
838
+                || ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
839
+                continue;
840
+            }
841
+
842
+            $known[] = $share->getId();
843
+            try {
844
+                /** @var IShare $share */
845
+                $format = $this->formatShare($share, $node);
846
+                $formatted[] = $format;
847
+
848
+                // let's also build a list of shares created
849
+                // by the current user only, in case
850
+                // there is no resharing rights
851
+                if ($share->getSharedBy() === $this->currentUser) {
852
+                    $miniFormatted[] = $format;
853
+                }
854
+
855
+                // check if one of those share is shared with me
856
+                // and if I have resharing rights on it
857
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
858
+                    $resharingRight = true;
859
+                }
860
+            } catch (InvalidPathException | NotFoundException $e) {
861
+            }
862
+        }
863
+
864
+        if (!$resharingRight) {
865
+            $formatted = $miniFormatted;
866
+        }
867
+
868
+        if ($includeTags) {
869
+            $formatted =
870
+                Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
871
+        }
872
+
873
+        return $formatted;
874
+    }
875
+
876
+
877
+    /**
878
+     * The getInheritedShares function.
879
+     * returns all shares relative to a file, including parent folders shares rights.
880
+     *
881
+     * @NoAdminRequired
882
+     *
883
+     * @param string $path
884
+     *
885
+     * - Get shares by the current user
886
+     * - Get shares by the current user and reshares (?reshares=true)
887
+     * - Get shares with the current user (?shared_with_me=true)
888
+     * - Get shares for a specific path (?path=...)
889
+     * - Get all shares in a folder (?subfiles=true&path=..)
890
+     *
891
+     * @return DataResponse
892
+     * @throws InvalidPathException
893
+     * @throws NotFoundException
894
+     * @throws OCSNotFoundException
895
+     * @throws OCSBadRequestException
896
+     * @throws SharingRightsException
897
+     */
898
+    public function getInheritedShares(string $path): DataResponse {
899
+
900
+        // get Node from (string) path.
901
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
902
+        try {
903
+            $node = $userFolder->get($path);
904
+            $this->lock($node);
905
+        } catch (\OCP\Files\NotFoundException $e) {
906
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
907
+        } catch (LockedException $e) {
908
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
909
+        }
910
+
911
+        if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
912
+            throw new SharingRightsException('no sharing rights on this item');
913
+        }
914
+
915
+        // The current top parent we have access to
916
+        $parent = $node;
917
+
918
+        // initiate real owner.
919
+        $owner = $node->getOwner()
920
+                        ->getUID();
921
+        if (!$this->userManager->userExists($owner)) {
922
+            return new DataResponse([]);
923
+        }
924
+
925
+        // get node based on the owner, fix owner in case of external storage
926
+        $userFolder = $this->rootFolder->getUserFolder($owner);
927
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
928
+            $owner = $node->getOwner()
929
+                            ->getUID();
930
+            $userFolder = $this->rootFolder->getUserFolder($owner);
931
+            $nodes = $userFolder->getById($node->getId());
932
+            $node = array_shift($nodes);
933
+        }
934
+        $basePath = $userFolder->getPath();
935
+
936
+        // generate node list for each parent folders
937
+        /** @var Node[] $nodes */
938
+        $nodes = [];
939
+        while ($node->getPath() !== $basePath) {
940
+            $node = $node->getParent();
941
+            $nodes[] = $node;
942
+        }
943
+
944
+        // The user that is requesting this list
945
+        $currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
946
+
947
+        // for each nodes, retrieve shares.
948
+        $shares = [];
949
+
950
+        foreach ($nodes as $node) {
951
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
952
+
953
+            $currentUserNodes = $currentUserFolder->getById($node->getId());
954
+            if (!empty($currentUserNodes)) {
955
+                $parent = array_pop($currentUserNodes);
956
+            }
957
+
958
+            $subPath = $currentUserFolder->getRelativePath($parent->getPath());
959
+            foreach ($getShares as &$share) {
960
+                $share['via_fileid'] = $parent->getId();
961
+                $share['via_path'] = $subPath;
962
+            }
963
+            $this->mergeFormattedShares($shares, $getShares);
964
+        }
965
+
966
+        return new DataResponse(array_values($shares));
967
+    }
968
+
969
+
970
+    /**
971
+     * @NoAdminRequired
972
+     *
973
+     * @param string $id
974
+     * @param int $permissions
975
+     * @param string $password
976
+     * @param string $sendPasswordByTalk
977
+     * @param string $publicUpload
978
+     * @param string $expireDate
979
+     * @param string $note
980
+     * @param string $label
981
+     * @param string $hideDownload
982
+     * @return DataResponse
983
+     * @throws LockedException
984
+     * @throws NotFoundException
985
+     * @throws OCSBadRequestException
986
+     * @throws OCSForbiddenException
987
+     * @throws OCSNotFoundException
988
+     */
989
+    public function updateShare(
990
+        string $id,
991
+        int $permissions = null,
992
+        string $password = null,
993
+        string $sendPasswordByTalk = null,
994
+        string $publicUpload = null,
995
+        string $expireDate = null,
996
+        string $note = null,
997
+        string $label = null,
998
+        string $hideDownload = null
999
+    ): DataResponse {
1000
+        try {
1001
+            $share = $this->getShareById($id);
1002
+        } catch (ShareNotFound $e) {
1003
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1004
+        }
1005
+
1006
+        $this->lock($share->getNode());
1007
+
1008
+        if (!$this->canAccessShare($share, false)) {
1009
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1010
+        }
1011
+
1012
+        if (!$this->canEditShare($share)) {
1013
+            throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1014
+        }
1015
+
1016
+        if (
1017
+            $permissions === null &&
1018
+            $password === null &&
1019
+            $sendPasswordByTalk === null &&
1020
+            $publicUpload === null &&
1021
+            $expireDate === null &&
1022
+            $note === null &&
1023
+            $label === null &&
1024
+            $hideDownload === null
1025
+        ) {
1026
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1027
+        }
1028
+
1029
+        if ($note !== null) {
1030
+            $share->setNote($note);
1031
+        }
1032
+
1033
+        /**
1034
+         * expirationdate, password and publicUpload only make sense for link shares
1035
+         */
1036
+        if ($share->getShareType() === IShare::TYPE_LINK
1037
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1038
+
1039
+            /**
1040
+             * We do not allow editing link shares that the current user
1041
+             * doesn't own. This is confusing and lead to errors when
1042
+             * someone else edit a password or expiration date without
1043
+             * the share owner knowing about it.
1044
+             * We only allow deletion
1045
+             */
1046
+
1047
+            if ($share->getSharedBy() !== $this->currentUser) {
1048
+                throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1049
+            }
1050
+
1051
+            // Update hide download state
1052
+            if ($hideDownload === 'true') {
1053
+                $share->setHideDownload(true);
1054
+            } elseif ($hideDownload === 'false') {
1055
+                $share->setHideDownload(false);
1056
+            }
1057
+
1058
+            $newPermissions = null;
1059
+            if ($publicUpload === 'true') {
1060
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1061
+            } elseif ($publicUpload === 'false') {
1062
+                $newPermissions = Constants::PERMISSION_READ;
1063
+            }
1064
+
1065
+            if ($permissions !== null) {
1066
+                $newPermissions = (int) $permissions;
1067
+                $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1068
+            }
1069
+
1070
+            if ($newPermissions !== null &&
1071
+                !in_array($newPermissions, [
1072
+                    Constants::PERMISSION_READ,
1073
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1074
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1075
+                    Constants::PERMISSION_CREATE, // hidden file list
1076
+                    Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1077
+                ], true)
1078
+            ) {
1079
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1080
+            }
1081
+
1082
+            if (
1083
+                // legacy
1084
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1085
+                // correct
1086
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1087
+            ) {
1088
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1089
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1090
+                }
1091
+
1092
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1093
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1094
+                }
1095
+
1096
+                // normalize to correct public upload permissions
1097
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1098
+            }
1099
+
1100
+            if ($newPermissions !== null) {
1101
+                // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1102
+                if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1103
+                    $newPermissions |= Constants::PERMISSION_SHARE;
1104
+                }
1105
+
1106
+                $share->setPermissions($newPermissions);
1107
+                $permissions = $newPermissions;
1108
+            }
1109
+
1110
+            if ($expireDate === '') {
1111
+                $share->setExpirationDate(null);
1112
+            } elseif ($expireDate !== null) {
1113
+                try {
1114
+                    $expireDate = $this->parseDate($expireDate);
1115
+                } catch (\Exception $e) {
1116
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1117
+                }
1118
+                $share->setExpirationDate($expireDate);
1119
+            }
1120
+
1121
+            if ($password === '') {
1122
+                $share->setPassword(null);
1123
+            } elseif ($password !== null) {
1124
+                $share->setPassword($password);
1125
+            }
1126
+
1127
+            // only link shares have labels
1128
+            if ($share->getShareType() === IShare::TYPE_LINK && $label !== null) {
1129
+                if (strlen($label) > 255) {
1130
+                    throw new OCSBadRequestException("Maxmimum label length is 255");
1131
+                }
1132
+                $share->setLabel($label);
1133
+            }
1134
+
1135
+            if ($sendPasswordByTalk === 'true') {
1136
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1137
+                    throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1138
+                }
1139
+
1140
+                $share->setSendPasswordByTalk(true);
1141
+            } elseif ($sendPasswordByTalk !== null) {
1142
+                $share->setSendPasswordByTalk(false);
1143
+            }
1144
+        }
1145
+
1146
+        // NOT A LINK SHARE
1147
+        else {
1148
+            if ($permissions !== null) {
1149
+                $permissions = (int) $permissions;
1150
+                $share->setPermissions($permissions);
1151
+            }
1152
+
1153
+            if ($expireDate === '') {
1154
+                $share->setExpirationDate(null);
1155
+            } elseif ($expireDate !== null) {
1156
+                try {
1157
+                    $expireDate = $this->parseDate($expireDate);
1158
+                } catch (\Exception $e) {
1159
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1160
+                }
1161
+                $share->setExpirationDate($expireDate);
1162
+            }
1163
+        }
1164
+
1165
+        try {
1166
+            $share = $this->shareManager->updateShare($share);
1167
+        } catch (GenericShareException $e) {
1168
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1169
+            throw new OCSException($e->getHint(), $code);
1170
+        } catch (\Exception $e) {
1171
+            throw new OCSBadRequestException($e->getMessage(), $e);
1172
+        }
1173
+
1174
+        return new DataResponse($this->formatShare($share));
1175
+    }
1176
+
1177
+    /**
1178
+     * @NoAdminRequired
1179
+     */
1180
+    public function pendingShares(): DataResponse {
1181
+        $pendingShares = [];
1182
+
1183
+        $shareTypes = [
1184
+            IShare::TYPE_USER,
1185
+            IShare::TYPE_GROUP
1186
+        ];
1187
+
1188
+        foreach ($shareTypes as $shareType) {
1189
+            $shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1190
+
1191
+            foreach ($shares as $share) {
1192
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1193
+                    $pendingShares[] = $share;
1194
+                }
1195
+            }
1196
+        }
1197
+
1198
+        $result = array_filter(array_map(function (IShare $share) {
1199
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1200
+            $nodes = $userFolder->getById($share->getNodeId());
1201
+            if (empty($nodes)) {
1202
+                // fallback to guessing the path
1203
+                $node = $userFolder->get($share->getTarget());
1204
+                if ($node === null || $share->getTarget() === '') {
1205
+                    return null;
1206
+                }
1207
+            } else {
1208
+                $node = $nodes[0];
1209
+            }
1210
+
1211
+            try {
1212
+                $formattedShare = $this->formatShare($share, $node);
1213
+                $formattedShare['status'] = $share->getStatus();
1214
+                $formattedShare['path'] = $share->getNode()->getName();
1215
+                $formattedShare['permissions'] = 0;
1216
+                return $formattedShare;
1217
+            } catch (NotFoundException $e) {
1218
+                return null;
1219
+            }
1220
+        }, $pendingShares), function ($entry) {
1221
+            return $entry !== null;
1222
+        });
1223
+
1224
+        return new DataResponse($result);
1225
+    }
1226
+
1227
+    /**
1228
+     * @NoAdminRequired
1229
+     *
1230
+     * @param string $id
1231
+     * @return DataResponse
1232
+     * @throws OCSNotFoundException
1233
+     * @throws OCSException
1234
+     * @throws OCSBadRequestException
1235
+     */
1236
+    public function acceptShare(string $id): DataResponse {
1237
+        try {
1238
+            $share = $this->getShareById($id);
1239
+        } catch (ShareNotFound $e) {
1240
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1241
+        }
1242
+
1243
+        if (!$this->canAccessShare($share)) {
1244
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1245
+        }
1246
+
1247
+        try {
1248
+            $this->shareManager->acceptShare($share, $this->currentUser);
1249
+        } catch (GenericShareException $e) {
1250
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1251
+            throw new OCSException($e->getHint(), $code);
1252
+        } catch (\Exception $e) {
1253
+            throw new OCSBadRequestException($e->getMessage(), $e);
1254
+        }
1255
+
1256
+        return new DataResponse();
1257
+    }
1258
+
1259
+    /**
1260
+     * Does the user have read permission on the share
1261
+     *
1262
+     * @param \OCP\Share\IShare $share the share to check
1263
+     * @param boolean $checkGroups check groups as well?
1264
+     * @return boolean
1265
+     * @throws NotFoundException
1266
+     *
1267
+     * @suppress PhanUndeclaredClassMethod
1268
+     */
1269
+    protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1270
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1271
+        if ($share->getPermissions() === 0) {
1272
+            return false;
1273
+        }
1274
+
1275
+        // Owner of the file and the sharer of the file can always get share
1276
+        if ($share->getShareOwner() === $this->currentUser
1277
+            || $share->getSharedBy() === $this->currentUser) {
1278
+            return true;
1279
+        }
1280
+
1281
+        // If the share is shared with you, you can access it!
1282
+        if ($share->getShareType() === IShare::TYPE_USER
1283
+            && $share->getSharedWith() === $this->currentUser) {
1284
+            return true;
1285
+        }
1286
+
1287
+        // Have reshare rights on the shared file/folder ?
1288
+        // Does the currentUser have access to the shared file?
1289
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1290
+        $files = $userFolder->getById($share->getNodeId());
1291
+        if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1292
+            return true;
1293
+        }
1294
+
1295
+        // If in the recipient group, you can see the share
1296
+        if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1297
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1298
+            $user = $this->userManager->get($this->currentUser);
1299
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1300
+                return true;
1301
+            }
1302
+        }
1303
+
1304
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1305
+            // TODO: have a sanity check like above?
1306
+            return true;
1307
+        }
1308
+
1309
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1310
+            try {
1311
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1312
+            } catch (QueryException $e) {
1313
+                return false;
1314
+            }
1315
+        }
1316
+
1317
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1318
+            try {
1319
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1320
+            } catch (QueryException $e) {
1321
+                return false;
1322
+            }
1323
+        }
1324
+
1325
+        return false;
1326
+    }
1327
+
1328
+    /**
1329
+     * Does the user have edit permission on the share
1330
+     *
1331
+     * @param \OCP\Share\IShare $share the share to check
1332
+     * @return boolean
1333
+     */
1334
+    protected function canEditShare(\OCP\Share\IShare $share): bool {
1335
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1336
+        if ($share->getPermissions() === 0) {
1337
+            return false;
1338
+        }
1339
+
1340
+        // The owner of the file and the creator of the share
1341
+        // can always edit the share
1342
+        if ($share->getShareOwner() === $this->currentUser ||
1343
+            $share->getSharedBy() === $this->currentUser
1344
+        ) {
1345
+            return true;
1346
+        }
1347
+
1348
+        //! we do NOT support some kind of `admin` in groups.
1349
+        //! You cannot edit shares shared to a group you're
1350
+        //! a member of if you're not the share owner or the file owner!
1351
+
1352
+        return false;
1353
+    }
1354
+
1355
+    /**
1356
+     * Does the user have delete permission on the share
1357
+     *
1358
+     * @param \OCP\Share\IShare $share the share to check
1359
+     * @return boolean
1360
+     */
1361
+    protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1362
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1363
+        if ($share->getPermissions() === 0) {
1364
+            return false;
1365
+        }
1366
+
1367
+        // if the user is the recipient, i can unshare
1368
+        // the share with self
1369
+        if ($share->getShareType() === IShare::TYPE_USER &&
1370
+            $share->getSharedWith() === $this->currentUser
1371
+        ) {
1372
+            return true;
1373
+        }
1374
+
1375
+        // The owner of the file and the creator of the share
1376
+        // can always delete the share
1377
+        if ($share->getShareOwner() === $this->currentUser ||
1378
+            $share->getSharedBy() === $this->currentUser
1379
+        ) {
1380
+            return true;
1381
+        }
1382
+
1383
+        return false;
1384
+    }
1385
+
1386
+    /**
1387
+     * Does the user have delete permission on the share
1388
+     * This differs from the canDeleteShare function as it only
1389
+     * remove the share for the current user. It does NOT
1390
+     * completely delete the share but only the mount point.
1391
+     * It can then be restored from the deleted shares section.
1392
+     *
1393
+     * @param \OCP\Share\IShare $share the share to check
1394
+     * @return boolean
1395
+     *
1396
+     * @suppress PhanUndeclaredClassMethod
1397
+     */
1398
+    protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1399
+        if ($share->getShareType() !== IShare::TYPE_GROUP &&
1400
+            $share->getShareType() !== IShare::TYPE_ROOM &&
1401
+            $share->getShareType() !== IShare::TYPE_DECK
1402
+        ) {
1403
+            return false;
1404
+        }
1405
+
1406
+        if ($share->getShareOwner() === $this->currentUser ||
1407
+            $share->getSharedBy() === $this->currentUser
1408
+        ) {
1409
+            // Delete the whole share, not just for self
1410
+            return false;
1411
+        }
1412
+
1413
+        // If in the recipient group, you can delete the share from self
1414
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1415
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1416
+            $user = $this->userManager->get($this->currentUser);
1417
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1418
+                return true;
1419
+            }
1420
+        }
1421
+
1422
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1423
+            try {
1424
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1425
+            } catch (QueryException $e) {
1426
+                return false;
1427
+            }
1428
+        }
1429
+
1430
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1431
+            try {
1432
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1433
+            } catch (QueryException $e) {
1434
+                return false;
1435
+            }
1436
+        }
1437
+
1438
+        return false;
1439
+    }
1440
+
1441
+    /**
1442
+     * Make sure that the passed date is valid ISO 8601
1443
+     * So YYYY-MM-DD
1444
+     * If not throw an exception
1445
+     *
1446
+     * @param string $expireDate
1447
+     *
1448
+     * @throws \Exception
1449
+     * @return \DateTime
1450
+     */
1451
+    private function parseDate(string $expireDate): \DateTime {
1452
+        try {
1453
+            $date = new \DateTime($expireDate);
1454
+        } catch (\Exception $e) {
1455
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1456
+        }
1457
+
1458
+        if ($date === false) {
1459
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1460
+        }
1461
+
1462
+        $date->setTime(0, 0, 0);
1463
+
1464
+        return $date;
1465
+    }
1466
+
1467
+    /**
1468
+     * Since we have multiple providers but the OCS Share API v1 does
1469
+     * not support this we need to check all backends.
1470
+     *
1471
+     * @param string $id
1472
+     * @return \OCP\Share\IShare
1473
+     * @throws ShareNotFound
1474
+     */
1475
+    private function getShareById(string $id): IShare {
1476
+        $share = null;
1477
+
1478
+        // First check if it is an internal share.
1479
+        try {
1480
+            $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1481
+            return $share;
1482
+        } catch (ShareNotFound $e) {
1483
+            // Do nothing, just try the other share type
1484
+        }
1485
+
1486
+
1487
+        try {
1488
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1489
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1490
+                return $share;
1491
+            }
1492
+        } catch (ShareNotFound $e) {
1493
+            // Do nothing, just try the other share type
1494
+        }
1495
+
1496
+        try {
1497
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1498
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1499
+                return $share;
1500
+            }
1501
+        } catch (ShareNotFound $e) {
1502
+            // Do nothing, just try the other share type
1503
+        }
1504
+
1505
+        try {
1506
+            $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1507
+            return $share;
1508
+        } catch (ShareNotFound $e) {
1509
+            // Do nothing, just try the other share type
1510
+        }
1511
+
1512
+        try {
1513
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1514
+                $share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1515
+                return $share;
1516
+            }
1517
+        } catch (ShareNotFound $e) {
1518
+            // Do nothing, just try the other share type
1519
+        }
1520
+
1521
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1522
+            throw new ShareNotFound();
1523
+        }
1524
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1525
+
1526
+        return $share;
1527
+    }
1528
+
1529
+    /**
1530
+     * Lock a Node
1531
+     *
1532
+     * @param \OCP\Files\Node $node
1533
+     * @throws LockedException
1534
+     */
1535
+    private function lock(\OCP\Files\Node $node) {
1536
+        $node->lock(ILockingProvider::LOCK_SHARED);
1537
+        $this->lockedNode = $node;
1538
+    }
1539
+
1540
+    /**
1541
+     * Cleanup the remaining locks
1542
+     * @throws LockedException
1543
+     */
1544
+    public function cleanup() {
1545
+        if ($this->lockedNode !== null) {
1546
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1547
+        }
1548
+    }
1549
+
1550
+    /**
1551
+     * Returns the helper of ShareAPIController for room shares.
1552
+     *
1553
+     * If the Talk application is not enabled or the helper is not available
1554
+     * a QueryException is thrown instead.
1555
+     *
1556
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1557
+     * @throws QueryException
1558
+     */
1559
+    private function getRoomShareHelper() {
1560
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1561
+            throw new QueryException();
1562
+        }
1563
+
1564
+        return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1565
+    }
1566
+
1567
+    /**
1568
+     * Returns the helper of ShareAPIHelper for deck shares.
1569
+     *
1570
+     * If the Deck application is not enabled or the helper is not available
1571
+     * a QueryException is thrown instead.
1572
+     *
1573
+     * @return \OCA\Deck\Sharing\ShareAPIHelper
1574
+     * @throws QueryException
1575
+     */
1576
+    private function getDeckShareHelper() {
1577
+        if (!$this->appManager->isEnabledForUser('deck')) {
1578
+            throw new QueryException();
1579
+        }
1580
+
1581
+        return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1582
+    }
1583
+
1584
+    /**
1585
+     * @param string $viewer
1586
+     * @param Node $node
1587
+     * @param bool $reShares
1588
+     *
1589
+     * @return IShare[]
1590
+     */
1591
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1592
+        $providers = [
1593
+            IShare::TYPE_USER,
1594
+            IShare::TYPE_GROUP,
1595
+            IShare::TYPE_LINK,
1596
+            IShare::TYPE_EMAIL,
1597
+            IShare::TYPE_EMAIL,
1598
+            IShare::TYPE_CIRCLE,
1599
+            IShare::TYPE_ROOM,
1600
+            IShare::TYPE_DECK
1601
+        ];
1602
+
1603
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1604
+        $shares = [];
1605
+        foreach ($providers as $provider) {
1606
+            if (!$this->shareManager->shareProviderExists($provider)) {
1607
+                continue;
1608
+            }
1609
+
1610
+            $providerShares =
1611
+                $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1612
+            $shares = array_merge($shares, $providerShares);
1613
+        }
1614
+
1615
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1616
+            $federatedShares = $this->shareManager->getSharesBy(
1617
+                $this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1618
+            );
1619
+            $shares = array_merge($shares, $federatedShares);
1620
+        }
1621
+
1622
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1623
+            $federatedShares = $this->shareManager->getSharesBy(
1624
+                $this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1625
+            );
1626
+            $shares = array_merge($shares, $federatedShares);
1627
+        }
1628
+
1629
+        return $shares;
1630
+    }
1631
+
1632
+
1633
+    /**
1634
+     * @param Node $node
1635
+     *
1636
+     * @throws SharingRightsException
1637
+     */
1638
+    private function confirmSharingRights(Node $node): void {
1639
+        if (!$this->hasResharingRights($this->currentUser, $node)) {
1640
+            throw new SharingRightsException('no sharing rights on this item');
1641
+        }
1642
+    }
1643
+
1644
+
1645
+    /**
1646
+     * @param string $viewer
1647
+     * @param Node $node
1648
+     *
1649
+     * @return bool
1650
+     */
1651
+    private function hasResharingRights($viewer, $node): bool {
1652
+        if ($viewer === $node->getOwner()->getUID()) {
1653
+            return true;
1654
+        }
1655
+
1656
+        foreach ([$node, $node->getParent()] as $node) {
1657
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1658
+            foreach ($shares as $share) {
1659
+                try {
1660
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1661
+                        return true;
1662
+                    }
1663
+                } catch (InvalidPathException | NotFoundException $e) {
1664
+                }
1665
+            }
1666
+        }
1667
+
1668
+        return false;
1669
+    }
1670
+
1671
+
1672
+    /**
1673
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1674
+     *
1675
+     * @suppress PhanUndeclaredClassMethod
1676
+     *
1677
+     * @param string $userId
1678
+     * @param IShare $share
1679
+     * @param Node $node
1680
+     *
1681
+     * @return bool
1682
+     * @throws NotFoundException
1683
+     * @throws InvalidPathException
1684
+     */
1685
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1686
+        if ($share->getShareOwner() === $userId) {
1687
+            return true;
1688
+        }
1689
+
1690
+        // we check that current user have parent resharing rights on the current file
1691
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1692
+            return true;
1693
+        }
1694
+
1695
+        if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1696
+            return false;
1697
+        }
1698
+
1699
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1700
+            return true;
1701
+        }
1702
+
1703
+        if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1704
+            return true;
1705
+        }
1706
+
1707
+        if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1708
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1709
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1710
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1711
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1712
+            if ($shareWithLength === false) {
1713
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart);
1714
+            } else {
1715
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1716
+            }
1717
+            try {
1718
+                $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1719
+                if ($member->getLevel() >= 4) {
1720
+                    return true;
1721
+                }
1722
+                return false;
1723
+            } catch (QueryException $e) {
1724
+                return false;
1725
+            }
1726
+        }
1727
+
1728
+        return false;
1729
+    }
1730
+
1731
+    /**
1732
+     * Get all the shares for the current user
1733
+     *
1734
+     * @param Node|null $path
1735
+     * @param boolean $reshares
1736
+     * @return IShare[]
1737
+     */
1738
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
1739
+        // Get all shares
1740
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1741
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1742
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1743
+
1744
+        // EMAIL SHARES
1745
+        $mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1746
+
1747
+        // CIRCLE SHARES
1748
+        $circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1749
+
1750
+        // TALK SHARES
1751
+        $roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1752
+
1753
+        $deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1754
+
1755
+        // FEDERATION
1756
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1757
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1758
+        } else {
1759
+            $federatedShares = [];
1760
+        }
1761
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1762
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1763
+        } else {
1764
+            $federatedGroupShares = [];
1765
+        }
1766
+
1767
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1768
+    }
1769
+
1770
+
1771
+    /**
1772
+     * merging already formatted shares.
1773
+     * We'll make an associative array to easily detect duplicate Ids.
1774
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
1775
+     *
1776
+     * @param array $shares
1777
+     * @param array $newShares
1778
+     */
1779
+    private function mergeFormattedShares(array &$shares, array $newShares) {
1780
+        foreach ($newShares as $newShare) {
1781
+            if (!array_key_exists($newShare['id'], $shares)) {
1782
+                $shares[$newShare['id']] = $newShare;
1783
+            }
1784
+        }
1785
+    }
1786 1786
 }
Please login to merge, or discard this patch.
lib/private/Collaboration/Collaborators/RemotePlugin.php 1 patch
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -38,155 +38,155 @@
 block discarded – undo
38 38
 use OCP\Share\IShare;
39 39
 
40 40
 class RemotePlugin implements ISearchPlugin {
41
-	protected $shareeEnumeration;
41
+    protected $shareeEnumeration;
42 42
 
43
-	/** @var IManager */
44
-	private $contactsManager;
45
-	/** @var ICloudIdManager */
46
-	private $cloudIdManager;
47
-	/** @var IConfig */
48
-	private $config;
49
-	/** @var IUserManager */
50
-	private $userManager;
51
-	/** @var string */
52
-	private $userId = '';
43
+    /** @var IManager */
44
+    private $contactsManager;
45
+    /** @var ICloudIdManager */
46
+    private $cloudIdManager;
47
+    /** @var IConfig */
48
+    private $config;
49
+    /** @var IUserManager */
50
+    private $userManager;
51
+    /** @var string */
52
+    private $userId = '';
53 53
 
54
-	public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
55
-		$this->contactsManager = $contactsManager;
56
-		$this->cloudIdManager = $cloudIdManager;
57
-		$this->config = $config;
58
-		$this->userManager = $userManager;
59
-		$user = $userSession->getUser();
60
-		if ($user !== null) {
61
-			$this->userId = $user->getUID();
62
-		}
63
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
64
-	}
54
+    public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
55
+        $this->contactsManager = $contactsManager;
56
+        $this->cloudIdManager = $cloudIdManager;
57
+        $this->config = $config;
58
+        $this->userManager = $userManager;
59
+        $user = $userSession->getUser();
60
+        if ($user !== null) {
61
+            $this->userId = $user->getUID();
62
+        }
63
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
64
+    }
65 65
 
66
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
67
-		$result = ['wide' => [], 'exact' => []];
68
-		$resultType = new SearchResultType('remotes');
66
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
67
+        $result = ['wide' => [], 'exact' => []];
68
+        $resultType = new SearchResultType('remotes');
69 69
 
70
-		// Search in contacts
71
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN'], ['limit' => $limit, 'offset' => $offset]);
72
-		foreach ($addressBookContacts as $contact) {
73
-			if (isset($contact['isLocalSystemBook'])) {
74
-				continue;
75
-			}
76
-			if (isset($contact['CLOUD'])) {
77
-				$cloudIds = $contact['CLOUD'];
78
-				if (is_string($cloudIds)) {
79
-					$cloudIds = [$cloudIds];
80
-				}
81
-				$lowerSearch = strtolower($search);
82
-				foreach ($cloudIds as $cloudId) {
83
-					$cloudIdType = '';
84
-					if (\is_array($cloudId)) {
85
-						$cloudIdData = $cloudId;
86
-						$cloudId = $cloudIdData['value'];
87
-						$cloudIdType = $cloudIdData['type'];
88
-					}
89
-					try {
90
-						list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
91
-					} catch (\InvalidArgumentException $e) {
92
-						continue;
93
-					}
70
+        // Search in contacts
71
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN'], ['limit' => $limit, 'offset' => $offset]);
72
+        foreach ($addressBookContacts as $contact) {
73
+            if (isset($contact['isLocalSystemBook'])) {
74
+                continue;
75
+            }
76
+            if (isset($contact['CLOUD'])) {
77
+                $cloudIds = $contact['CLOUD'];
78
+                if (is_string($cloudIds)) {
79
+                    $cloudIds = [$cloudIds];
80
+                }
81
+                $lowerSearch = strtolower($search);
82
+                foreach ($cloudIds as $cloudId) {
83
+                    $cloudIdType = '';
84
+                    if (\is_array($cloudId)) {
85
+                        $cloudIdData = $cloudId;
86
+                        $cloudId = $cloudIdData['value'];
87
+                        $cloudIdType = $cloudIdData['type'];
88
+                    }
89
+                    try {
90
+                        list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
91
+                    } catch (\InvalidArgumentException $e) {
92
+                        continue;
93
+                    }
94 94
 
95
-					$localUser = $this->userManager->get($remoteUser);
96
-					/**
97
-					 * Add local share if remote cloud id matches a local user ones
98
-					 */
99
-					if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
100
-						$result['wide'][] = [
101
-							'label' => $contact['FN'],
102
-							'uuid' => $contact['UID'],
103
-							'value' => [
104
-								'shareType' => IShare::TYPE_USER,
105
-								'shareWith' => $remoteUser
106
-							],
107
-							'shareWithDisplayNameUnique' => $contact['EMAIL'] !== null && $contact['EMAIL'] !== '' ? $contact['EMAIL'] : $contact['UID'],
108
-						];
109
-					}
95
+                    $localUser = $this->userManager->get($remoteUser);
96
+                    /**
97
+                     * Add local share if remote cloud id matches a local user ones
98
+                     */
99
+                    if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
100
+                        $result['wide'][] = [
101
+                            'label' => $contact['FN'],
102
+                            'uuid' => $contact['UID'],
103
+                            'value' => [
104
+                                'shareType' => IShare::TYPE_USER,
105
+                                'shareWith' => $remoteUser
106
+                            ],
107
+                            'shareWithDisplayNameUnique' => $contact['EMAIL'] !== null && $contact['EMAIL'] !== '' ? $contact['EMAIL'] : $contact['UID'],
108
+                        ];
109
+                    }
110 110
 
111
-					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
112
-						if (strtolower($cloudId) === $lowerSearch) {
113
-							$searchResult->markExactIdMatch($resultType);
114
-						}
115
-						$result['exact'][] = [
116
-							'label' => $contact['FN'] . " ($cloudId)",
117
-							'uuid' => $contact['UID'],
118
-							'name' => $contact['FN'],
119
-							'type' => $cloudIdType,
120
-							'value' => [
121
-								'shareType' => IShare::TYPE_REMOTE,
122
-								'shareWith' => $cloudId,
123
-								'server' => $serverUrl,
124
-							],
125
-						];
126
-					} else {
127
-						$result['wide'][] = [
128
-							'label' => $contact['FN'] . " ($cloudId)",
129
-							'uuid' => $contact['UID'],
130
-							'name' => $contact['FN'],
131
-							'type' => $cloudIdType,
132
-							'value' => [
133
-								'shareType' => IShare::TYPE_REMOTE,
134
-								'shareWith' => $cloudId,
135
-								'server' => $serverUrl,
136
-							],
137
-						];
138
-					}
139
-				}
140
-			}
141
-		}
111
+                    if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
112
+                        if (strtolower($cloudId) === $lowerSearch) {
113
+                            $searchResult->markExactIdMatch($resultType);
114
+                        }
115
+                        $result['exact'][] = [
116
+                            'label' => $contact['FN'] . " ($cloudId)",
117
+                            'uuid' => $contact['UID'],
118
+                            'name' => $contact['FN'],
119
+                            'type' => $cloudIdType,
120
+                            'value' => [
121
+                                'shareType' => IShare::TYPE_REMOTE,
122
+                                'shareWith' => $cloudId,
123
+                                'server' => $serverUrl,
124
+                            ],
125
+                        ];
126
+                    } else {
127
+                        $result['wide'][] = [
128
+                            'label' => $contact['FN'] . " ($cloudId)",
129
+                            'uuid' => $contact['UID'],
130
+                            'name' => $contact['FN'],
131
+                            'type' => $cloudIdType,
132
+                            'value' => [
133
+                                'shareType' => IShare::TYPE_REMOTE,
134
+                                'shareWith' => $cloudId,
135
+                                'server' => $serverUrl,
136
+                            ],
137
+                        ];
138
+                    }
139
+                }
140
+            }
141
+        }
142 142
 
143
-		if (!$this->shareeEnumeration) {
144
-			$result['wide'] = [];
145
-		} else {
146
-			$result['wide'] = array_slice($result['wide'], $offset, $limit);
147
-		}
143
+        if (!$this->shareeEnumeration) {
144
+            $result['wide'] = [];
145
+        } else {
146
+            $result['wide'] = array_slice($result['wide'], $offset, $limit);
147
+        }
148 148
 
149
-		/**
150
-		 * Add generic share with remote item for valid cloud ids that are not users of the local instance
151
-		 */
152
-		if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
153
-			try {
154
-				list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
155
-				$localUser = $this->userManager->get($remoteUser);
156
-				if ($localUser === null || $search !== $localUser->getCloudId()) {
157
-					$result['exact'][] = [
158
-						'label' => $remoteUser . " ($serverUrl)",
159
-						'uuid' => $remoteUser,
160
-						'name' => $remoteUser,
161
-						'value' => [
162
-							'shareType' => IShare::TYPE_REMOTE,
163
-							'shareWith' => $search,
164
-							'server' => $serverUrl,
165
-						],
166
-					];
167
-				}
168
-			} catch (\InvalidArgumentException $e) {
169
-			}
170
-		}
149
+        /**
150
+         * Add generic share with remote item for valid cloud ids that are not users of the local instance
151
+         */
152
+        if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
153
+            try {
154
+                list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
155
+                $localUser = $this->userManager->get($remoteUser);
156
+                if ($localUser === null || $search !== $localUser->getCloudId()) {
157
+                    $result['exact'][] = [
158
+                        'label' => $remoteUser . " ($serverUrl)",
159
+                        'uuid' => $remoteUser,
160
+                        'name' => $remoteUser,
161
+                        'value' => [
162
+                            'shareType' => IShare::TYPE_REMOTE,
163
+                            'shareWith' => $search,
164
+                            'server' => $serverUrl,
165
+                        ],
166
+                    ];
167
+                }
168
+            } catch (\InvalidArgumentException $e) {
169
+            }
170
+        }
171 171
 
172
-		$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
172
+        $searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
173 173
 
174
-		return true;
175
-	}
174
+        return true;
175
+    }
176 176
 
177
-	/**
178
-	 * split user and remote from federated cloud id
179
-	 *
180
-	 * @param string $address federated share address
181
-	 * @return array [user, remoteURL]
182
-	 * @throws \InvalidArgumentException
183
-	 */
184
-	public function splitUserRemote($address) {
185
-		try {
186
-			$cloudId = $this->cloudIdManager->resolveCloudId($address);
187
-			return [$cloudId->getUser(), $cloudId->getRemote()];
188
-		} catch (\InvalidArgumentException $e) {
189
-			throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
190
-		}
191
-	}
177
+    /**
178
+     * split user and remote from federated cloud id
179
+     *
180
+     * @param string $address federated share address
181
+     * @return array [user, remoteURL]
182
+     * @throws \InvalidArgumentException
183
+     */
184
+    public function splitUserRemote($address) {
185
+        try {
186
+            $cloudId = $this->cloudIdManager->resolveCloudId($address);
187
+            return [$cloudId->getUser(), $cloudId->getRemote()];
188
+        } catch (\InvalidArgumentException $e) {
189
+            throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
190
+        }
191
+    }
192 192
 }
Please login to merge, or discard this patch.
lib/private/Collaboration/Collaborators/MailPlugin.php 1 patch
Indentation   +205 added lines, -205 removed lines patch added patch discarded remove patch
@@ -40,211 +40,211 @@
 block discarded – undo
40 40
 use OCP\Share\IShare;
41 41
 
42 42
 class MailPlugin implements ISearchPlugin {
43
-	protected $shareeEnumeration;
44
-	protected $shareWithGroupOnly;
45
-
46
-	/** @var IManager */
47
-	private $contactsManager;
48
-	/** @var ICloudIdManager */
49
-	private $cloudIdManager;
50
-	/** @var IConfig */
51
-	private $config;
52
-
53
-	/** @var IGroupManager */
54
-	private $groupManager;
55
-
56
-	/** @var IUserSession */
57
-	private $userSession;
58
-
59
-	public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IGroupManager $groupManager, IUserSession $userSession) {
60
-		$this->contactsManager = $contactsManager;
61
-		$this->cloudIdManager = $cloudIdManager;
62
-		$this->config = $config;
63
-		$this->groupManager = $groupManager;
64
-		$this->userSession = $userSession;
65
-
66
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
67
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
68
-		$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
69
-	}
70
-
71
-	/**
72
-	 * @param $search
73
-	 * @param $limit
74
-	 * @param $offset
75
-	 * @param ISearchResult $searchResult
76
-	 * @return bool
77
-	 * @since 13.0.0
78
-	 */
79
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
80
-		$result = $userResults = ['wide' => [], 'exact' => []];
81
-		$userType = new SearchResultType('users');
82
-		$emailType = new SearchResultType('emails');
83
-
84
-		// Search in contacts
85
-		$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN'], ['limit' => $limit, 'offset' => $offset]);
86
-		$lowerSearch = strtolower($search);
87
-		foreach ($addressBookContacts as $contact) {
88
-			if (isset($contact['EMAIL'])) {
89
-				$emailAddresses = $contact['EMAIL'];
90
-				if (\is_string($emailAddresses)) {
91
-					$emailAddresses = [$emailAddresses];
92
-				}
93
-				foreach ($emailAddresses as $type => $emailAddress) {
94
-					$displayName = $emailAddress;
95
-					$emailAddressType = null;
96
-					if (\is_array($emailAddress)) {
97
-						$emailAddressData = $emailAddress;
98
-						$emailAddress = $emailAddressData['value'];
99
-						$emailAddressType = $emailAddressData['type'];
100
-					}
101
-					if (isset($contact['FN'])) {
102
-						$displayName = $contact['FN'] . ' (' . $emailAddress . ')';
103
-					}
104
-					$exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
105
-
106
-					if (isset($contact['isLocalSystemBook'])) {
107
-						if ($this->shareWithGroupOnly) {
108
-							/*
43
+    protected $shareeEnumeration;
44
+    protected $shareWithGroupOnly;
45
+
46
+    /** @var IManager */
47
+    private $contactsManager;
48
+    /** @var ICloudIdManager */
49
+    private $cloudIdManager;
50
+    /** @var IConfig */
51
+    private $config;
52
+
53
+    /** @var IGroupManager */
54
+    private $groupManager;
55
+
56
+    /** @var IUserSession */
57
+    private $userSession;
58
+
59
+    public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IGroupManager $groupManager, IUserSession $userSession) {
60
+        $this->contactsManager = $contactsManager;
61
+        $this->cloudIdManager = $cloudIdManager;
62
+        $this->config = $config;
63
+        $this->groupManager = $groupManager;
64
+        $this->userSession = $userSession;
65
+
66
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
67
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
68
+        $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
69
+    }
70
+
71
+    /**
72
+     * @param $search
73
+     * @param $limit
74
+     * @param $offset
75
+     * @param ISearchResult $searchResult
76
+     * @return bool
77
+     * @since 13.0.0
78
+     */
79
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
80
+        $result = $userResults = ['wide' => [], 'exact' => []];
81
+        $userType = new SearchResultType('users');
82
+        $emailType = new SearchResultType('emails');
83
+
84
+        // Search in contacts
85
+        $addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN'], ['limit' => $limit, 'offset' => $offset]);
86
+        $lowerSearch = strtolower($search);
87
+        foreach ($addressBookContacts as $contact) {
88
+            if (isset($contact['EMAIL'])) {
89
+                $emailAddresses = $contact['EMAIL'];
90
+                if (\is_string($emailAddresses)) {
91
+                    $emailAddresses = [$emailAddresses];
92
+                }
93
+                foreach ($emailAddresses as $type => $emailAddress) {
94
+                    $displayName = $emailAddress;
95
+                    $emailAddressType = null;
96
+                    if (\is_array($emailAddress)) {
97
+                        $emailAddressData = $emailAddress;
98
+                        $emailAddress = $emailAddressData['value'];
99
+                        $emailAddressType = $emailAddressData['type'];
100
+                    }
101
+                    if (isset($contact['FN'])) {
102
+                        $displayName = $contact['FN'] . ' (' . $emailAddress . ')';
103
+                    }
104
+                    $exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
105
+
106
+                    if (isset($contact['isLocalSystemBook'])) {
107
+                        if ($this->shareWithGroupOnly) {
108
+                            /*
109 109
 							 * Check if the user may share with the user associated with the e-mail of the just found contact
110 110
 							 */
111
-							$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
112
-							$found = false;
113
-							foreach ($userGroups as $userGroup) {
114
-								if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
115
-									$found = true;
116
-									break;
117
-								}
118
-							}
119
-							if (!$found) {
120
-								continue;
121
-							}
122
-						}
123
-						if ($exactEmailMatch) {
124
-							try {
125
-								$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
126
-							} catch (\InvalidArgumentException $e) {
127
-								continue;
128
-							}
129
-
130
-							if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
131
-								$singleResult = [[
132
-									'label' => $displayName,
133
-									'uuid' => $contact['UID'],
134
-									'name' => $contact['FN'],
135
-									'value' => [
136
-										'shareType' => IShare::TYPE_USER,
137
-										'shareWith' => $cloud->getUser(),
138
-									],
139
-									'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
140
-
141
-								]];
142
-								$searchResult->addResultSet($userType, [], $singleResult);
143
-								$searchResult->markExactIdMatch($emailType);
144
-							}
145
-							return false;
146
-						}
147
-
148
-						if ($this->shareeEnumeration) {
149
-							try {
150
-								$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
151
-							} catch (\InvalidArgumentException $e) {
152
-								continue;
153
-							}
154
-
155
-							$addToWide = !$this->shareeEnumerationInGroupOnly;
156
-							if ($this->shareeEnumerationInGroupOnly) {
157
-								$addToWide = false;
158
-								$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
159
-								foreach ($userGroups as $userGroup) {
160
-									if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
161
-										$addToWide = true;
162
-										break;
163
-									}
164
-								}
165
-							}
166
-							if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
167
-								$userResults['wide'][] = [
168
-									'label' => $displayName,
169
-									'uuid' => $contact['UID'],
170
-									'name' => $contact['FN'],
171
-									'value' => [
172
-										'shareType' => IShare::TYPE_USER,
173
-										'shareWith' => $cloud->getUser(),
174
-									],
175
-									'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
176
-								];
177
-								continue;
178
-							}
179
-						}
180
-						continue;
181
-					}
182
-
183
-					if ($exactEmailMatch
184
-						|| isset($contact['FN']) && strtolower($contact['FN']) === $lowerSearch) {
185
-						if ($exactEmailMatch) {
186
-							$searchResult->markExactIdMatch($emailType);
187
-						}
188
-						$result['exact'][] = [
189
-							'label' => $displayName,
190
-							'uuid' => $contact['UID'],
191
-							'name' => $contact['FN'],
192
-							'type' => $emailAddressType ?? '',
193
-							'value' => [
194
-								'shareType' => IShare::TYPE_EMAIL,
195
-								'shareWith' => $emailAddress,
196
-							],
197
-						];
198
-					} else {
199
-						$result['wide'][] = [
200
-							'label' => $displayName,
201
-							'uuid' => $contact['UID'],
202
-							'name' => $contact['FN'],
203
-							'type' => $emailAddressType ?? '',
204
-							'value' => [
205
-								'shareType' => IShare::TYPE_EMAIL,
206
-								'shareWith' => $emailAddress,
207
-							],
208
-						];
209
-					}
210
-				}
211
-			}
212
-		}
213
-
214
-		$reachedEnd = true;
215
-		if (!$this->shareeEnumeration) {
216
-			$result['wide'] = [];
217
-			$userResults['wide'] = [];
218
-		} else {
219
-			$reachedEnd = (count($result['wide']) < $offset + $limit) &&
220
-				(count($userResults['wide']) < $offset + $limit);
221
-
222
-			$result['wide'] = array_slice($result['wide'], $offset, $limit);
223
-			$userResults['wide'] = array_slice($userResults['wide'], $offset, $limit);
224
-		}
225
-
226
-
227
-		if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) {
228
-			$result['exact'][] = [
229
-				'label' => $search,
230
-				'uuid' => $search,
231
-				'value' => [
232
-					'shareType' => IShare::TYPE_EMAIL,
233
-					'shareWith' => $search,
234
-				],
235
-			];
236
-		}
237
-
238
-		if (!empty($userResults['wide'])) {
239
-			$searchResult->addResultSet($userType, $userResults['wide'], []);
240
-		}
241
-		$searchResult->addResultSet($emailType, $result['wide'], $result['exact']);
242
-
243
-		return !$reachedEnd;
244
-	}
245
-
246
-	public function isCurrentUser(ICloudId $cloud): bool {
247
-		$currentUser = $this->userSession->getUser();
248
-		return $currentUser instanceof IUser ? $currentUser->getUID() === $cloud->getUser() : false;
249
-	}
111
+                            $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
112
+                            $found = false;
113
+                            foreach ($userGroups as $userGroup) {
114
+                                if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
115
+                                    $found = true;
116
+                                    break;
117
+                                }
118
+                            }
119
+                            if (!$found) {
120
+                                continue;
121
+                            }
122
+                        }
123
+                        if ($exactEmailMatch) {
124
+                            try {
125
+                                $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
126
+                            } catch (\InvalidArgumentException $e) {
127
+                                continue;
128
+                            }
129
+
130
+                            if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
131
+                                $singleResult = [[
132
+                                    'label' => $displayName,
133
+                                    'uuid' => $contact['UID'],
134
+                                    'name' => $contact['FN'],
135
+                                    'value' => [
136
+                                        'shareType' => IShare::TYPE_USER,
137
+                                        'shareWith' => $cloud->getUser(),
138
+                                    ],
139
+                                    'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
140
+
141
+                                ]];
142
+                                $searchResult->addResultSet($userType, [], $singleResult);
143
+                                $searchResult->markExactIdMatch($emailType);
144
+                            }
145
+                            return false;
146
+                        }
147
+
148
+                        if ($this->shareeEnumeration) {
149
+                            try {
150
+                                $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
151
+                            } catch (\InvalidArgumentException $e) {
152
+                                continue;
153
+                            }
154
+
155
+                            $addToWide = !$this->shareeEnumerationInGroupOnly;
156
+                            if ($this->shareeEnumerationInGroupOnly) {
157
+                                $addToWide = false;
158
+                                $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
159
+                                foreach ($userGroups as $userGroup) {
160
+                                    if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
161
+                                        $addToWide = true;
162
+                                        break;
163
+                                    }
164
+                                }
165
+                            }
166
+                            if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
167
+                                $userResults['wide'][] = [
168
+                                    'label' => $displayName,
169
+                                    'uuid' => $contact['UID'],
170
+                                    'name' => $contact['FN'],
171
+                                    'value' => [
172
+                                        'shareType' => IShare::TYPE_USER,
173
+                                        'shareWith' => $cloud->getUser(),
174
+                                    ],
175
+                                    'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
176
+                                ];
177
+                                continue;
178
+                            }
179
+                        }
180
+                        continue;
181
+                    }
182
+
183
+                    if ($exactEmailMatch
184
+                        || isset($contact['FN']) && strtolower($contact['FN']) === $lowerSearch) {
185
+                        if ($exactEmailMatch) {
186
+                            $searchResult->markExactIdMatch($emailType);
187
+                        }
188
+                        $result['exact'][] = [
189
+                            'label' => $displayName,
190
+                            'uuid' => $contact['UID'],
191
+                            'name' => $contact['FN'],
192
+                            'type' => $emailAddressType ?? '',
193
+                            'value' => [
194
+                                'shareType' => IShare::TYPE_EMAIL,
195
+                                'shareWith' => $emailAddress,
196
+                            ],
197
+                        ];
198
+                    } else {
199
+                        $result['wide'][] = [
200
+                            'label' => $displayName,
201
+                            'uuid' => $contact['UID'],
202
+                            'name' => $contact['FN'],
203
+                            'type' => $emailAddressType ?? '',
204
+                            'value' => [
205
+                                'shareType' => IShare::TYPE_EMAIL,
206
+                                'shareWith' => $emailAddress,
207
+                            ],
208
+                        ];
209
+                    }
210
+                }
211
+            }
212
+        }
213
+
214
+        $reachedEnd = true;
215
+        if (!$this->shareeEnumeration) {
216
+            $result['wide'] = [];
217
+            $userResults['wide'] = [];
218
+        } else {
219
+            $reachedEnd = (count($result['wide']) < $offset + $limit) &&
220
+                (count($userResults['wide']) < $offset + $limit);
221
+
222
+            $result['wide'] = array_slice($result['wide'], $offset, $limit);
223
+            $userResults['wide'] = array_slice($userResults['wide'], $offset, $limit);
224
+        }
225
+
226
+
227
+        if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) {
228
+            $result['exact'][] = [
229
+                'label' => $search,
230
+                'uuid' => $search,
231
+                'value' => [
232
+                    'shareType' => IShare::TYPE_EMAIL,
233
+                    'shareWith' => $search,
234
+                ],
235
+            ];
236
+        }
237
+
238
+        if (!empty($userResults['wide'])) {
239
+            $searchResult->addResultSet($userType, $userResults['wide'], []);
240
+        }
241
+        $searchResult->addResultSet($emailType, $result['wide'], $result['exact']);
242
+
243
+        return !$reachedEnd;
244
+    }
245
+
246
+    public function isCurrentUser(ICloudId $cloud): bool {
247
+        $currentUser = $this->userSession->getUser();
248
+        return $currentUser instanceof IUser ? $currentUser->getUID() === $cloud->getUser() : false;
249
+    }
250 250
 }
Please login to merge, or discard this patch.
lib/private/Collaboration/Collaborators/UserPlugin.php 1 patch
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -43,218 +43,218 @@
 block discarded – undo
43 43
 use OCP\UserStatus\IManager as IUserStatusManager;
44 44
 
45 45
 class UserPlugin implements ISearchPlugin {
46
-	/* @var bool */
47
-	protected $shareWithGroupOnly;
48
-	protected $shareeEnumeration;
49
-	protected $shareeEnumerationInGroupOnly;
46
+    /* @var bool */
47
+    protected $shareWithGroupOnly;
48
+    protected $shareeEnumeration;
49
+    protected $shareeEnumerationInGroupOnly;
50 50
 
51
-	/** @var IConfig */
52
-	private $config;
53
-	/** @var IGroupManager */
54
-	private $groupManager;
55
-	/** @var IUserSession */
56
-	private $userSession;
57
-	/** @var IUserManager */
58
-	private $userManager;
59
-	/** @var IUserStatusManager */
60
-	private $userStatusManager;
51
+    /** @var IConfig */
52
+    private $config;
53
+    /** @var IGroupManager */
54
+    private $groupManager;
55
+    /** @var IUserSession */
56
+    private $userSession;
57
+    /** @var IUserManager */
58
+    private $userManager;
59
+    /** @var IUserStatusManager */
60
+    private $userStatusManager;
61 61
 
62
-	/**
63
-	 * UserPlugin constructor.
64
-	 *
65
-	 * @param IConfig $config
66
-	 * @param IUserManager $userManager
67
-	 * @param IGroupManager $groupManager
68
-	 * @param IUserSession $userSession
69
-	 * @param IUserStatusManager $userStatusManager
70
-	 */
71
-	public function __construct(IConfig $config,
72
-								IUserManager $userManager,
73
-								IGroupManager $groupManager,
74
-								IUserSession $userSession,
75
-								IUserStatusManager $userStatusManager) {
76
-		$this->config = $config;
62
+    /**
63
+     * UserPlugin constructor.
64
+     *
65
+     * @param IConfig $config
66
+     * @param IUserManager $userManager
67
+     * @param IGroupManager $groupManager
68
+     * @param IUserSession $userSession
69
+     * @param IUserStatusManager $userStatusManager
70
+     */
71
+    public function __construct(IConfig $config,
72
+                                IUserManager $userManager,
73
+                                IGroupManager $groupManager,
74
+                                IUserSession $userSession,
75
+                                IUserStatusManager $userStatusManager) {
76
+        $this->config = $config;
77 77
 
78
-		$this->groupManager = $groupManager;
79
-		$this->userSession = $userSession;
80
-		$this->userManager = $userManager;
81
-		$this->userStatusManager = $userStatusManager;
78
+        $this->groupManager = $groupManager;
79
+        $this->userSession = $userSession;
80
+        $this->userManager = $userManager;
81
+        $this->userStatusManager = $userStatusManager;
82 82
 
83
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
84
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
85
-		$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
86
-	}
83
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
84
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
85
+        $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
86
+    }
87 87
 
88
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
89
-		$result = ['wide' => [], 'exact' => []];
90
-		$users = [];
91
-		$hasMoreResults = false;
88
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
89
+        $result = ['wide' => [], 'exact' => []];
90
+        $users = [];
91
+        $hasMoreResults = false;
92 92
 
93
-		$currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
94
-		if ($this->shareWithGroupOnly) {
95
-			// Search in all the groups this user is part of
96
-			foreach ($currentUserGroups as $userGroupId) {
97
-				$usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
98
-				foreach ($usersInGroup as $userId => $displayName) {
99
-					$userId = (string) $userId;
100
-					$user = $this->userManager->get($userId);
101
-					if (!$user->isEnabled()) {
102
-						// Ignore disabled users
103
-						continue;
104
-					}
105
-					$users[$userId] = $user;
106
-				}
107
-				if (count($usersInGroup) >= $limit) {
108
-					$hasMoreResults = true;
109
-				}
110
-			}
111
-		} else {
112
-			// Search in all users
113
-			$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
114
-			foreach ($usersTmp as $user) {
115
-				if ($user->isEnabled()) { // Don't keep deactivated users
116
-					$users[$user->getUID()] = $user;
117
-				}
118
-			}
119
-		}
93
+        $currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
94
+        if ($this->shareWithGroupOnly) {
95
+            // Search in all the groups this user is part of
96
+            foreach ($currentUserGroups as $userGroupId) {
97
+                $usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
98
+                foreach ($usersInGroup as $userId => $displayName) {
99
+                    $userId = (string) $userId;
100
+                    $user = $this->userManager->get($userId);
101
+                    if (!$user->isEnabled()) {
102
+                        // Ignore disabled users
103
+                        continue;
104
+                    }
105
+                    $users[$userId] = $user;
106
+                }
107
+                if (count($usersInGroup) >= $limit) {
108
+                    $hasMoreResults = true;
109
+                }
110
+            }
111
+        } else {
112
+            // Search in all users
113
+            $usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
114
+            foreach ($usersTmp as $user) {
115
+                if ($user->isEnabled()) { // Don't keep deactivated users
116
+                    $users[$user->getUID()] = $user;
117
+                }
118
+            }
119
+        }
120 120
 
121
-		$this->takeOutCurrentUser($users);
121
+        $this->takeOutCurrentUser($users);
122 122
 
123
-		if (!$this->shareeEnumeration || count($users) < $limit) {
124
-			$hasMoreResults = true;
125
-		}
123
+        if (!$this->shareeEnumeration || count($users) < $limit) {
124
+            $hasMoreResults = true;
125
+        }
126 126
 
127
-		$foundUserById = false;
128
-		$lowerSearch = strtolower($search);
129
-		$userStatuses = $this->userStatusManager->getUserStatuses(array_keys($users));
130
-		foreach ($users as $uid => $user) {
131
-			$userDisplayName = $user->getDisplayName();
132
-			$userEmail = $user->getEMailAddress();
133
-			$uid = (string) $uid;
127
+        $foundUserById = false;
128
+        $lowerSearch = strtolower($search);
129
+        $userStatuses = $this->userStatusManager->getUserStatuses(array_keys($users));
130
+        foreach ($users as $uid => $user) {
131
+            $userDisplayName = $user->getDisplayName();
132
+            $userEmail = $user->getEMailAddress();
133
+            $uid = (string) $uid;
134 134
 
135
-			$status = [];
136
-			if (array_key_exists($uid, $userStatuses)) {
137
-				$userStatus = $userStatuses[$uid];
138
-				$status = [
139
-					'status' => $userStatus->getStatus(),
140
-					'message' => $userStatus->getMessage(),
141
-					'icon' => $userStatus->getIcon(),
142
-					'clearAt' => $userStatus->getClearAt()
143
-						? (int)$userStatus->getClearAt()->format('U')
144
-						: null,
145
-				];
146
-			}
135
+            $status = [];
136
+            if (array_key_exists($uid, $userStatuses)) {
137
+                $userStatus = $userStatuses[$uid];
138
+                $status = [
139
+                    'status' => $userStatus->getStatus(),
140
+                    'message' => $userStatus->getMessage(),
141
+                    'icon' => $userStatus->getIcon(),
142
+                    'clearAt' => $userStatus->getClearAt()
143
+                        ? (int)$userStatus->getClearAt()->format('U')
144
+                        : null,
145
+                ];
146
+            }
147 147
 
148 148
 
149
-			if (
150
-				$lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
151
-				strtolower($userDisplayName) === $lowerSearch ||
152
-				strtolower($userEmail) === $lowerSearch)
153
-			) {
154
-				if (strtolower($uid) === $lowerSearch) {
155
-					$foundUserById = true;
156
-				}
157
-				$result['exact'][] = [
158
-					'label' => $userDisplayName,
159
-					'subline' => $status['message'] ?? '',
160
-					'icon' => 'icon-user',
161
-					'value' => [
162
-						'shareType' => IShare::TYPE_USER,
163
-						'shareWith' => $uid,
164
-					],
165
-					'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
166
-					'status' => $status,
167
-				];
168
-			} else {
169
-				$addToWideResults = false;
170
-				if ($this->shareeEnumeration && !$this->shareeEnumerationInGroupOnly) {
171
-					$addToWideResults = true;
172
-				}
149
+            if (
150
+                $lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
151
+                strtolower($userDisplayName) === $lowerSearch ||
152
+                strtolower($userEmail) === $lowerSearch)
153
+            ) {
154
+                if (strtolower($uid) === $lowerSearch) {
155
+                    $foundUserById = true;
156
+                }
157
+                $result['exact'][] = [
158
+                    'label' => $userDisplayName,
159
+                    'subline' => $status['message'] ?? '',
160
+                    'icon' => 'icon-user',
161
+                    'value' => [
162
+                        'shareType' => IShare::TYPE_USER,
163
+                        'shareWith' => $uid,
164
+                    ],
165
+                    'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
166
+                    'status' => $status,
167
+                ];
168
+            } else {
169
+                $addToWideResults = false;
170
+                if ($this->shareeEnumeration && !$this->shareeEnumerationInGroupOnly) {
171
+                    $addToWideResults = true;
172
+                }
173 173
 
174
-				if ($this->shareeEnumerationInGroupOnly) {
175
-					$commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
176
-					if (!empty($commonGroups)) {
177
-						$addToWideResults = true;
178
-					}
179
-				}
174
+                if ($this->shareeEnumerationInGroupOnly) {
175
+                    $commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
176
+                    if (!empty($commonGroups)) {
177
+                        $addToWideResults = true;
178
+                    }
179
+                }
180 180
 
181
-				if ($addToWideResults) {
182
-					$result['wide'][] = [
183
-						'label' => $userDisplayName,
184
-						'subline' => $status['message'] ?? '',
185
-						'icon' => 'icon-user',
186
-						'value' => [
187
-							'shareType' => IShare::TYPE_USER,
188
-							'shareWith' => $uid,
189
-						],
190
-						'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
191
-						'status' => $status,
192
-					];
193
-				}
194
-			}
195
-		}
181
+                if ($addToWideResults) {
182
+                    $result['wide'][] = [
183
+                        'label' => $userDisplayName,
184
+                        'subline' => $status['message'] ?? '',
185
+                        'icon' => 'icon-user',
186
+                        'value' => [
187
+                            'shareType' => IShare::TYPE_USER,
188
+                            'shareWith' => $uid,
189
+                        ],
190
+                        'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
191
+                        'status' => $status,
192
+                    ];
193
+                }
194
+            }
195
+        }
196 196
 
197
-		if ($offset === 0 && !$foundUserById) {
198
-			// On page one we try if the search result has a direct hit on the
199
-			// user id and if so, we add that to the exact match list
200
-			$user = $this->userManager->get($search);
201
-			if ($user instanceof IUser) {
202
-				$addUser = true;
197
+        if ($offset === 0 && !$foundUserById) {
198
+            // On page one we try if the search result has a direct hit on the
199
+            // user id and if so, we add that to the exact match list
200
+            $user = $this->userManager->get($search);
201
+            if ($user instanceof IUser) {
202
+                $addUser = true;
203 203
 
204
-				if ($this->shareWithGroupOnly) {
205
-					// Only add, if we have a common group
206
-					$commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
207
-					$addUser = !empty($commonGroups);
208
-				}
204
+                if ($this->shareWithGroupOnly) {
205
+                    // Only add, if we have a common group
206
+                    $commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
207
+                    $addUser = !empty($commonGroups);
208
+                }
209 209
 
210
-				if ($addUser) {
211
-					$status = [];
212
-					$uid = $user->getUID();
213
-					$userEmail = $user->getEMailAddress();
214
-					if (array_key_exists($user->getUID(), $userStatuses)) {
215
-						$userStatus = $userStatuses[$user->getUID()];
216
-						$status = [
217
-							'status' => $userStatus->getStatus(),
218
-							'message' => $userStatus->getMessage(),
219
-							'icon' => $userStatus->getIcon(),
220
-							'clearAt' => $userStatus->getClearAt()
221
-								? (int)$userStatus->getClearAt()->format('U')
222
-								: null,
223
-						];
224
-					}
210
+                if ($addUser) {
211
+                    $status = [];
212
+                    $uid = $user->getUID();
213
+                    $userEmail = $user->getEMailAddress();
214
+                    if (array_key_exists($user->getUID(), $userStatuses)) {
215
+                        $userStatus = $userStatuses[$user->getUID()];
216
+                        $status = [
217
+                            'status' => $userStatus->getStatus(),
218
+                            'message' => $userStatus->getMessage(),
219
+                            'icon' => $userStatus->getIcon(),
220
+                            'clearAt' => $userStatus->getClearAt()
221
+                                ? (int)$userStatus->getClearAt()->format('U')
222
+                                : null,
223
+                        ];
224
+                    }
225 225
 
226
-					$result['exact'][] = [
227
-						'label' => $user->getDisplayName(),
228
-						'icon' => 'icon-user',
229
-						'subline' => $status['message'] ?? '',
230
-						'value' => [
231
-							'shareType' => IShare::TYPE_USER,
232
-							'shareWith' => $user->getUID(),
233
-						],
234
-						'shareWithDisplayNameUnique' => $userEmail !== null && $userEmail !== '' ? $userEmail : $uid,
235
-						'status' => $status,
236
-					];
237
-				}
238
-			}
239
-		}
226
+                    $result['exact'][] = [
227
+                        'label' => $user->getDisplayName(),
228
+                        'icon' => 'icon-user',
229
+                        'subline' => $status['message'] ?? '',
230
+                        'value' => [
231
+                            'shareType' => IShare::TYPE_USER,
232
+                            'shareWith' => $user->getUID(),
233
+                        ],
234
+                        'shareWithDisplayNameUnique' => $userEmail !== null && $userEmail !== '' ? $userEmail : $uid,
235
+                        'status' => $status,
236
+                    ];
237
+                }
238
+            }
239
+        }
240 240
 
241 241
 
242 242
 
243
-		$type = new SearchResultType('users');
244
-		$searchResult->addResultSet($type, $result['wide'], $result['exact']);
245
-		if (count($result['exact'])) {
246
-			$searchResult->markExactIdMatch($type);
247
-		}
243
+        $type = new SearchResultType('users');
244
+        $searchResult->addResultSet($type, $result['wide'], $result['exact']);
245
+        if (count($result['exact'])) {
246
+            $searchResult->markExactIdMatch($type);
247
+        }
248 248
 
249
-		return $hasMoreResults;
250
-	}
249
+        return $hasMoreResults;
250
+    }
251 251
 
252
-	public function takeOutCurrentUser(array &$users) {
253
-		$currentUser = $this->userSession->getUser();
254
-		if (!is_null($currentUser)) {
255
-			if (isset($users[$currentUser->getUID()])) {
256
-				unset($users[$currentUser->getUID()]);
257
-			}
258
-		}
259
-	}
252
+    public function takeOutCurrentUser(array &$users) {
253
+        $currentUser = $this->userSession->getUser();
254
+        if (!is_null($currentUser)) {
255
+            if (isset($users[$currentUser->getUID()])) {
256
+                unset($users[$currentUser->getUID()]);
257
+            }
258
+        }
259
+    }
260 260
 }
Please login to merge, or discard this patch.