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