Completed
Pull Request — master (#32767)
by Victor
09:41
created

Share20OcsController::deleteShare()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 28

Duplication

Lines 4
Ratio 14.29 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 1
dl 4
loc 28
rs 9.1608
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Viktar Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2018, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OCA\Files_Sharing\Controller;
23
24
use OCP\AppFramework\OCSController;
25
use OCP\Files\IRootFolder;
26
use OCP\Files\NotFoundException;
27
use OCP\IConfig;
28
use OCP\IGroupManager;
29
use OCP\IL10N;
30
use OCP\IRequest;
31
use OCP\IURLGenerator;
32
use OCP\IUser;
33
use OCP\IUserManager;
34
use OCP\Lock\ILockingProvider;
35
use OCP\Lock\LockedException;
36
use OCP\Share\Exceptions\GenericShareException;
37
use OCP\Share\Exceptions\ShareNotFound;
38
use OCP\Share\IManager;
39
use OCP\Share\IShare;
40
use OCA\Files_Sharing\Service\NotificationPublisher;
41
use OCA\Files_Sharing\Helper;
42
use OCA\Files_Sharing\SharingBlacklist;
43
use Symfony\Component\EventDispatcher\EventDispatcher;
44
use Symfony\Component\EventDispatcher\GenericEvent;
45
46
/**
47
 * Class Share20OcsController
48
 *
49
 * @package OCA\Files_Sharing\Controller
50
 */
51
class Share20OcsController extends OCSController {
52
	/** @var IManager */
53
	private $shareManager;
54
	/** @var IGroupManager */
55
	private $groupManager;
56
	/** @var IUserManager */
57
	private $userManager;
58
	/** @var IRootFolder */
59
	private $rootFolder;
60
	/** @var IURLGenerator */
61
	private $urlGenerator;
62
	/** @var IUser */
63
	private $currentUser;
64
	/** @var IL10N */
65
	private $l;
66
	/** @var IConfig */
67
	private $config;
68
	/** @var NotificationPublisher */
69
	private $notificationPublisher;
70
	/** @var EventDispatcher  */
71
	private $eventDispatcher;
72
	/** @var SharingBlacklist */
73
	private $sharingBlacklist;
74
75
	/**
76
	 * @var string
77
	 */
78
	private $additionalInfoField;
79
80
	public function __construct(
81
		$appName,
82
		IRequest $request,
83
		IManager $shareManager,
84
		IGroupManager $groupManager,
85
		IUserManager $userManager,
86
		IRootFolder $rootFolder,
87
		IURLGenerator $urlGenerator,
88
		IUser $currentUser,
89
		IL10N $l10n,
90
		IConfig $config,
91
		NotificationPublisher $notificationPublisher,
92
		EventDispatcher $eventDispatcher,
93
		SharingBlacklist $sharingBlacklist
94
	) {
95
		parent::__construct($appName, $request);
96
		$this->request = $request;
97
		$this->shareManager = $shareManager;
98
		$this->groupManager = $groupManager;
99
		$this->userManager = $userManager;
100
		$this->rootFolder = $rootFolder;
101
		$this->urlGenerator = $urlGenerator;
102
		$this->currentUser = $currentUser;
103
		$this->l = $l10n;
104
		$this->config = $config;
105
		$this->notificationPublisher = $notificationPublisher;
106
		$this->eventDispatcher = $eventDispatcher;
107
		$this->sharingBlacklist = $sharingBlacklist;
108
		$this->additionalInfoField = $this->config->getAppValue('core', 'user_additional_info_field', '');
109
	}
110
111
	/**
112
	 * Returns the additional info to display behind the display name as configured.
113
	 *
114
	 * @param IUser $user user for which to retrieve the additional info
115
	 * @return string|null additional info or null if none to be displayed
116
	 */
117 View Code Duplication
	private function getAdditionalUserInfo(IUser $user) {
118
		if ($this->additionalInfoField === 'email') {
119
			return $user->getEMailAddress();
120
		} elseif ($this->additionalInfoField === 'id') {
121
			return $user->getUID();
122
		}
123
		return null;
124
	}
125
126
	/**
127
	 * Convert an IShare to an array for OCS output
128
	 *
129
	 * @param \OCP\Share\IShare $share
130
	 * @param bool $received whether it's formatting received shares
131
	 * @return array
132
	 * @throws NotFoundException In case the node can't be resolved.
133
	 */
134
	protected function formatShare(\OCP\Share\IShare $share, $received = false) {
135
		$sharedBy = $this->userManager->get($share->getSharedBy());
136
		$shareOwner = $this->userManager->get($share->getShareOwner());
137
138
		$result = [
139
			'id' => $share->getId(),
140
			'share_type' => $share->getShareType(),
141
			'uid_owner' => $share->getSharedBy(),
142
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
143
			'permissions' => $share->getPermissions(),
144
			'stime' => $share->getShareTime() ? $share->getShareTime()->getTimestamp() : null,
145
			'parent' => null,
146
			'expiration' => null,
147
			'token' => null,
148
			'uid_file_owner' => $share->getShareOwner(),
149
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner()
150
		];
151
152
		if ($received) {
153
			// also add state
154
			$result['state'] = $share->getState();
155
156
			// can only fetch path info if mounted already or if owner
157
			if ($share->getState() === \OCP\Share::STATE_ACCEPTED || $share->getShareOwner() === $this->currentUser->getUID()) {
158
				$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
159
			} else {
160
				// need to go through owner user for pending shares
161
				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
162
			}
163
		} else {
164
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
165
		}
166
167
		$nodes = $userFolder->getById($share->getNodeId());
168
169
		if (empty($nodes)) {
170
			throw new NotFoundException();
171
		}
172
173
		$node = $nodes[0];
174
175
		$result['path'] = $userFolder->getRelativePath($node->getPath());
176
		if ($node instanceof \OCP\Files\Folder) {
177
			$result['item_type'] = 'folder';
178
		} else {
179
			$result['item_type'] = 'file';
180
		}
181
		$result['mimetype'] = $node->getMimeType();
182
		$result['storage_id'] = $node->getStorage()->getId();
183
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
184
		$result['item_source'] = \strval($node->getId());
185
		$result['file_source'] = \strval($node->getId());
186
		$result['file_parent'] = \strval($node->getParent()->getId());
187
		$result['file_target'] = $share->getTarget();
188
189
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
190
			$sharedWith = $this->userManager->get($share->getSharedWith());
191
			$result['share_with'] = $share->getSharedWith();
192
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
193
			if ($sharedWith !== null) {
194
				$result['share_with_additional_info'] = $this->getAdditionalUserInfo($sharedWith);
195
			}
196
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
197
			$group = $this->groupManager->get($share->getSharedWith());
198
			$result['share_with'] = $share->getSharedWith();
199
			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
200
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
201
			$result['share_with'] = $share->getPassword();
202
			$result['share_with_displayname'] = $share->getPassword();
203
			$result['name'] = $share->getName();
204
205
			$result['token'] = $share->getToken();
206
			if ($share->getToken() !== null) {
207
				$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
208
			}
209
210
			$expiration = $share->getExpirationDate();
211
			if ($expiration !== null) {
212
				$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
213
			}
214
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
215
			$result['share_with'] = $share->getSharedWith();
216
			$result['share_with_displayname'] = $share->getSharedWith();
217
			$result['token'] = $share->getToken();
218
		}
219
220
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
221
222
		return $result;
223
	}
224
225
	/**
226
	 * Get a specific share by id
227
	 *
228
	 * @NoCSRFRequired
229
	 * @NoAdminRequired
230
	 *
231
	 * @param string $id
232
	 * @return \OC\OCS\Result
233
	 */
234
	public function getShare($id) {
235
		if (!$this->shareManager->shareApiEnabled()) {
236
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
237
		}
238
239
		try {
240
			$share = $this->getShareById($id);
241
		} catch (ShareNotFound $e) {
242
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
243
		}
244
245
		if ($this->canAccessShare($share)) {
246
			try {
247
				$share = $this->formatShare($share);
248
				return new \OC\OCS\Result([$share]);
249
			} catch (NotFoundException $e) {
250
				//Fall trough
251
			}
252
		}
253
254
		return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
255
	}
256
257
	/**
258
	 * Delete a share
259
	 *
260
	 * @NoCSRFRequired
261
	 * @NoAdminRequired
262
	 *
263
	 * @param string $id
264
	 * @return \OC\OCS\Result
265
	 */
266
	public function deleteShare($id) {
267
		if (!$this->shareManager->shareApiEnabled()) {
268
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
269
		}
270
271
		try {
272
			$share = $this->getShareById($id);
273
		} catch (ShareNotFound $e) {
274
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
275
		}
276
277
		try {
278
			$share->getNode()->lock(ILockingProvider::LOCK_SHARED);
279
		} catch (LockedException $e) {
280
			return new \OC\OCS\Result(null, 404, 'could not delete share');
281
		}
282
283 View Code Duplication
		if (!$this->canAccessShare($share)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
284
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
285
			return new \OC\OCS\Result(null, 404, $this->l->t('Could not delete share'));
286
		}
287
288
		$this->shareManager->deleteShare($share);
289
290
		$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
291
292
		return new \OC\OCS\Result();
293
	}
294
295
	/**
296
	 * @NoCSRFRequired
297
	 * @NoAdminRequired
298
	 *
299
	 * @return \OC\OCS\Result
300
	 */
301
	public function createShare() {
302
		$share = $this->shareManager->newShare();
303
304
		if (!$this->shareManager->shareApiEnabled()) {
305
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
306
		}
307
308
		$name = $this->request->getParam('name', null);
309
310
		// Verify path
311
		$path = $this->request->getParam('path', null);
312
		if ($path === null) {
313
			return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a file or folder path'));
314
		}
315
316
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
317
318
		try {
319
			$path = $userFolder->get($path);
320
		} catch (NotFoundException $e) {
321
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong path, file/folder doesn\'t exist'));
322
		}
323
324
		$share->setNode($path);
325
326
		try {
327
			$share->getNode()->lock(ILockingProvider::LOCK_SHARED);
328
		} catch (LockedException $e) {
329
			return new \OC\OCS\Result(null, 404, 'Could not create share');
330
		}
331
332
		$shareType = (int)$this->request->getParam('shareType', '-1');
333
334
		// Parse permissions (if available)
335
		$permissions = $this->request->getParam('permissions', null);
336
		if ($permissions === null) {
337
			if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
338
				$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', \OCP\Constants::PERMISSION_ALL);
339
				$permissions |= \OCP\Constants::PERMISSION_READ;
340
			} else {
341
				$permissions = \OCP\Constants::PERMISSION_ALL;
342
			}
343
		} else {
344
			$permissions = (int)$permissions;
345
		}
346
347
		if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
348
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
349
			return new \OC\OCS\Result(null, 404, 'invalid permissions');
350
		}
351
352
		if ($permissions === 0) {
353
			return new \OC\OCS\Result(null, 400, $this->l->t('Cannot remove all permissions'));
354
		}
355
356
		// link shares can have create-only without read (anonymous upload)
357
		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK && $permissions !== \OCP\Constants::PERMISSION_CREATE) {
358
			// Shares always require read permissions
359
			$permissions |= \OCP\Constants::PERMISSION_READ;
360
		}
361
362
		if ($path instanceof \OCP\Files\File) {
363
			// Single file shares should never have delete or create permissions
364
			$permissions &= ~\OCP\Constants::PERMISSION_DELETE;
365
			$permissions &= ~\OCP\Constants::PERMISSION_CREATE;
366
		}
367
368
		/*
369
		 * Hack for https://github.com/owncloud/core/issues/22587
370
		 * We check the permissions via webdav. But the permissions of the mount point
371
		 * do not equal the share permissions. Here we fix that for federated mounts.
372
		 */
373
		if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
374
			$permissions &= ~($permissions & ~$path->getPermissions());
375
		}
376
377
		$shareWith = $this->request->getParam('shareWith', null);
378
379
		$autoAccept = $this->config->getAppValue('core', 'shareapi_auto_accept_share', 'yes') === 'yes';
380
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
381
			// Valid user is required to share
382
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
383
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
384
				return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a valid user'));
385
			}
386
			$share->setSharedWith($shareWith);
387
			$share->setPermissions($permissions);
388
			if ($autoAccept) {
389
				$share->setState(\OCP\Share::STATE_ACCEPTED);
390
			} else {
391
				$share->setState(\OCP\Share::STATE_PENDING);
392
			}
393
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
394
			if (!$this->shareManager->allowGroupSharing()) {
395
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
396
				return new \OC\OCS\Result(null, 404, $this->l->t('Group sharing is disabled by the administrator'));
397
			}
398
399
			// Valid group is required to share
400
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
401
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
402
				return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a valid group'));
403
			}
404
			if ($this->sharingBlacklist->isGroupBlacklisted($this->groupManager->get($shareWith))) {
405
				return new \OC\OCS\Result(null, 403, $this->l->t('The group is blacklisted for sharing'));
406
			}
407
			$share->setSharedWith($shareWith);
408
			$share->setPermissions($permissions);
409
			if ($autoAccept) {
410
				$share->setState(\OCP\Share::STATE_ACCEPTED);
411
			} else {
412
				$share->setState(\OCP\Share::STATE_PENDING);
413
			}
414
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
415
			//Can we even share links?
416
			if (!$this->shareManager->shareApiAllowLinks()) {
417
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
418
				return new \OC\OCS\Result(null, 404, $this->l->t('Public link sharing is disabled by the administrator'));
419
			}
420
421
			// legacy way, expecting that this won't be used together with "create-only" shares
422
			$publicUpload = $this->request->getParam('publicUpload', null);
423
			// a few permission checks
424 View Code Duplication
			if ($publicUpload === 'true' || $permissions === \OCP\Constants::PERMISSION_CREATE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
425
				// Check if public upload is allowed
426
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
427
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
428
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
429
				}
430
431
				// Public upload can only be set for folders
432
				if ($path instanceof \OCP\Files\File) {
433
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
434
					return new \OC\OCS\Result(null, 404, $this->l->t('Public upload is only possible for publicly shared folders'));
435
				}
436
			}
437
438
			// convert to permissions
439
			if ($publicUpload === 'true') {
440
				$share->setPermissions(
441
					\OCP\Constants::PERMISSION_READ |
442
					\OCP\Constants::PERMISSION_CREATE |
443
					\OCP\Constants::PERMISSION_UPDATE |
444
					\OCP\Constants::PERMISSION_DELETE
445
				);
446
			} elseif ($permissions === \OCP\Constants::PERMISSION_CREATE ||
447
				$permissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)) {
448
				$share->setPermissions($permissions);
449
			} else {
450
				// because when "publicUpload" is passed usually no permissions are set,
451
				// which defaults to ALL. But in the case of link shares we default to READ...
452
				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
453
			}
454
455
			// set name only if passed as parameter, empty string is allowed
456
			if ($name !== null) {
457
				$share->setName($name);
458
			}
459
460
			// Set password
461
			$password = $this->request->getParam('password', '');
462
463
			if ($password !== '') {
464
				$share->setPassword($password);
465
			}
466
467
			//Expire date
468
			$expireDate = $this->request->getParam('expireDate', '');
469
470
			if ($expireDate !== '') {
471
				try {
472
					$expireDate = $this->parseDate($expireDate);
473
					$share->setExpirationDate($expireDate);
474
				} catch (\Exception $e) {
475
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
476
					return new \OC\OCS\Result(null, 404, $this->l->t('Invalid date, date format must be YYYY-MM-DD'));
477
				}
478
			}
479
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
480
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
481
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
482
				return new \OC\OCS\Result(null, 403, $this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
483
			}
484
485
			$share->setSharedWith($shareWith);
486
			$share->setPermissions($permissions);
487 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
489
			return new \OC\OCS\Result(null, 400, $this->l->t('Unknown share type'));
490
		}
491
492
		$share->setShareType($shareType);
493
		$share->setSharedBy($this->currentUser->getUID());
494
495
		try {
496
			$share = $this->shareManager->createShare($share);
497
		} catch (GenericShareException $e) {
498
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
499
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
500
			return new \OC\OCS\Result(null, $code, $e->getHint());
501
		} catch (\Exception $e) {
502
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
503
			return new \OC\OCS\Result(null, 403, $e->getMessage());
504
		}
505
506
		$share->getNode()->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
507
508
		$formattedShareAfterCreate = $this->formatShare($share);
509
510
		return new \OC\OCS\Result($formattedShareAfterCreate);
511
	}
512
513
	/**
514
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
515
	 * @param boolean $includeTags include tags in response
516
	 * @param int|null $stateFilter state filter or empty for all, defaults to 0 (accepted)
517
	 * @return \OC\OCS\Result
518
	 */
519
	private function getSharedWithMe($node = null, $includeTags, $stateFilter = 0) {
520
		$userShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
521
		$groupShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
522
523
		$shares = \array_merge($userShares, $groupShares);
524
525
		$shares = \array_filter($shares, function (IShare $share) {
526
			return $share->getShareOwner() !== $this->currentUser->getUID();
527
		});
528
529
		$formatted = [];
530
		foreach ($shares as $share) {
531
			if (($stateFilter === null || $share->getState() === $stateFilter) &&
532
				$this->canAccessShare($share)) {
533
				try {
534
					$formatted[] = $this->formatShare($share, true);
535
				} catch (NotFoundException $e) {
536
					// Ignore this share
537
				}
538
			}
539
		}
540
541
		if ($includeTags) {
542
			$formatted = \OCA\Files\Helper::populateTags($formatted, 'file_source');
543
		}
544
545
		return new \OC\OCS\Result($formatted);
546
	}
547
548
	/**
549
	 * @param \OCP\Files\Folder $folder
550
	 * @return \OC\OCS\Result
551
	 */
552
	private function getSharesInDir($folder) {
553
		if (!($folder instanceof \OCP\Files\Folder)) {
554
			return new \OC\OCS\Result(null, 400, $this->l->t('Not a directory'));
555
		}
556
557
		$nodes = $folder->getDirectoryListing();
558
		/** @var \OCP\Share\IShare[] $shares */
559
		$shares = [];
560
		foreach ($nodes as $node) {
561
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
562
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
563
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
564
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
565
				$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
566
			}
567
		}
568
569
		$formatted = [];
570
		foreach ($shares as $share) {
571
			try {
572
				$formatted[] = $this->formatShare($share);
573
			} catch (NotFoundException $e) {
574
				//Ignore this share
575
			}
576
		}
577
578
		return new \OC\OCS\Result($formatted);
579
	}
580
581
	/**
582
	 * The getShares function.
583
	 *
584
	 * @NoCSRFRequired
585
	 * @NoAdminRequired
586
	 *
587
	 * - Get shares by the current user
588
	 * - Get shares by the current user and reshares (?reshares=true)
589
	 * - Get shares with the current user (?shared_with_me=true)
590
	 * - Get shares for a specific path (?path=...)
591
	 * - Get all shares in a folder (?subfiles=true&path=..)
592
	 *
593
	 * @return \OC\OCS\Result
594
	 */
595
	public function getShares() {
596
		if (!$this->shareManager->shareApiEnabled()) {
597
			return new \OC\OCS\Result();
598
		}
599
600
		$sharedWithMe = $this->request->getParam('shared_with_me', null);
601
		$reshares = $this->request->getParam('reshares', null);
602
		$subfiles = $this->request->getParam('subfiles');
603
		$path = $this->request->getParam('path', null);
604
605
		$includeTags = $this->request->getParam('include_tags', false);
606
607
		if ($path !== null) {
608
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
609
			try {
610
				$path = $userFolder->get($path);
611
				$path->lock(ILockingProvider::LOCK_SHARED);
612
			} catch (\OCP\Files\NotFoundException $e) {
613
				return new \OC\OCS\Result(null, 404, $this->l->t('Wrong path, file/folder doesn\'t exist'));
614
			} catch (LockedException $e) {
615
				return new \OC\OCS\Result(null, 404, $this->l->t('Could not lock path'));
616
			}
617
		}
618
619
		if ($sharedWithMe === 'true') {
620
			$stateFilter = $this->request->getParam('state', \OCP\Share::STATE_ACCEPTED);
621
			if ($stateFilter === '') {
622
				$stateFilter = \OCP\Share::STATE_ACCEPTED;
623
			} elseif ($stateFilter === 'all') {
624
				$stateFilter = null; // which means all
625
			} else {
626
				$stateFilter = (int)$stateFilter;
627
			}
628
			$result = $this->getSharedWithMe($path, $includeTags, $stateFilter);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCA\Files_Sharing\Contro...ller::getSharedWithMe() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
629
			if ($path !== null) {
630
				$path->unlock(ILockingProvider::LOCK_SHARED);
631
			}
632
			return $result;
633
		}
634
635
		if ($subfiles === 'true') {
636
			$result = $this->getSharesInDir($path);
0 ignored issues
show
Documentation introduced by
$path is of type object<OCP\Files\Node>|null, but the function expects a object<OCP\Files\Folder>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
637
			if ($path !== null) {
638
				$path->unlock(ILockingProvider::LOCK_SHARED);
639
			}
640
			return $result;
641
		}
642
643
		if ($reshares === 'true') {
644
			$reshares = true;
645
		} else {
646
			$reshares = false;
647
		}
648
649
		// Get all shares
650
		$userShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
651
		$groupShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
652
		$linkShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
653
		$shares = \array_merge($userShares, $groupShares, $linkShares);
654
655
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
656
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
657
			$shares = \array_merge($shares, $federatedShares);
658
		}
659
660
		$formatted = [];
661
		foreach ($shares as $share) {
662
			try {
663
				$formatted[] = $this->formatShare($share);
664
			} catch (NotFoundException $e) {
665
				//Ignore share
666
			}
667
		}
668
669
		if ($includeTags) {
670
			$formatted = \OCA\Files\Helper::populateTags($formatted, 'file_source');
671
		}
672
673
		if ($path !== null) {
674
			$path->unlock(ILockingProvider::LOCK_SHARED);
675
		}
676
677
		return new \OC\OCS\Result($formatted);
678
	}
679
680
	/**
681
	 * @NoCSRFRequired
682
	 * @NoAdminRequired
683
	 *
684
	 * @param int $id
685
	 * @return \OC\OCS\Result
686
	 */
687
	public function updateShare($id) {
688
		if (!$this->shareManager->shareApiEnabled()) {
689
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
690
		}
691
692
		try {
693
			$share = $this->getShareById($id);
694
		} catch (ShareNotFound $e) {
695
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
696
		}
697
698
		$share->getNode()->lock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
699
700 View Code Duplication
		if (!$this->canAccessShare($share)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
701
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
702
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
703
		}
704
705
		$permissions = $this->request->getParam('permissions', null);
706
		$password = $this->request->getParam('password', null);
707
		$publicUpload = $this->request->getParam('publicUpload', null);
708
		$expireDate = $this->request->getParam('expireDate', null);
709
		$name = $this->request->getParam('name', null);
710
711
		/*
712
		 * expirationdate, password and publicUpload only make sense for link shares
713
		 */
714
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
715
			if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null && $name === null) {
716
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
717
				return new \OC\OCS\Result(null, 400, 'Wrong or no update parameter given');
718
			}
719
720
			$newPermissions = null;
721
			if ($publicUpload === 'true') {
722
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
723
			} elseif ($publicUpload === 'false') {
724
				$newPermissions = \OCP\Constants::PERMISSION_READ;
725
			}
726
727
			if ($permissions !== null) {
728
				$newPermissions = (int)$permissions;
729
			}
730
731
			if ($newPermissions !== null &&
732
				$newPermissions !== \OCP\Constants::PERMISSION_READ &&
733
				$newPermissions !== \OCP\Constants::PERMISSION_CREATE &&
734
				// legacy
735
				$newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) &&
736
				// correct
737
				$newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
738
			) {
739
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
740
				return new \OC\OCS\Result(null, 400, $this->l->t('Can\'t change permissions for public share links'));
741
			}
742
743
			if (
744
				// legacy
745
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) ||
746
				// correct
747
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
748
			) {
749
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
750
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
751
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
752
				}
753
754
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
755
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
756
					return new \OC\OCS\Result(null, 400, $this->l->t('Public upload is only possible for publicly shared folders'));
757
				}
758
759
				// normalize to correct public upload permissions
760
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
761
			}
762
763
			// create-only (upload-only)
764 View Code Duplication
			if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
765
				$newPermissions === \OCP\Constants::PERMISSION_CREATE
766
			) {
767
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
768
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
769
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
770
				}
771
772
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
773
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
774
					return new \OC\OCS\Result(null, 400, $this->l->t('Public upload is only possible for publicly shared folders'));
775
				}
776
			}
777
778
			// set name only if passed as parameter, empty string is allowed
779
			if ($name !== null) {
780
				$oldname = $share->getName();
781
				$share->setName($name);
782
			}
783
784
			if ($newPermissions !== null) {
785
				$share->setPermissions($newPermissions);
786
				$permissions = $newPermissions;
787
			}
788
789
			if ($expireDate === '') {
790
				$share->setExpirationDate(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
791
			} elseif ($expireDate !== null) {
792
				try {
793
					$expireDate = $this->parseDate($expireDate);
794
				} catch (\Exception $e) {
795
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
796
					return new \OC\OCS\Result(null, 400, $e->getMessage());
797
				}
798
				$share->setExpirationDate($expireDate);
799
			}
800
801
			if ($password === '') {
802
				$share->setPassword(null);
803
			} elseif ($password !== null) {
804
				$share->setPassword($password);
805
			}
806
		} else {
807
			// For other shares only permissions is valid.
808
			if ($permissions === null) {
809
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
810
				return new \OC\OCS\Result(null, 400, $this->l->t('Wrong or no update parameter given'));
811
			} else {
812
				$permissions = (int)$permissions;
813
				$share->setPermissions($permissions);
814
			}
815
		}
816
817
		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser->getUID()) {
818
			/* Check if this is an incoming share */
819
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
820
			$incomingShares = \array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
821
822
			if (!empty($incomingShares)) {
823
				$maxPermissions = 0;
824
				foreach ($incomingShares as $incomingShare) {
825
					$maxPermissions |= $incomingShare->getPermissions();
826
				}
827
828
				if ($share->getPermissions() & ~$maxPermissions) {
829
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
830
					return new \OC\OCS\Result(null, 404, $this->l->t('Cannot increase permissions'));
831
				}
832
			}
833
		}
834
835
		if ($share->getPermissions() === 0) {
836
			return new \OC\OCS\Result(null, 400, $this->l->t('Cannot remove all permissions'));
837
		}
838
839
		try {
840
			$share = $this->shareManager->updateShare($share);
841
		} catch (\Exception $e) {
842
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
843
			return new \OC\OCS\Result(null, 400, $e->getMessage());
844
		}
845
846
		$share->getNode()->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
847
848
		return new \OC\OCS\Result($this->formatShare($share));
849
	}
850
851
	/**
852
	 * @NoCSRFRequired
853
	 * @NoAdminRequired
854
	 *
855
	 * @param int $id
856
	 * @return \OC\OCS\Result
857
	 */
858
	public function acceptShare($id) {
859
		return $this->updateShareState($id, \OCP\Share::STATE_ACCEPTED);
860
	}
861
862
	/**
863
	 * @NoCSRFRequired
864
	 * @NoAdminRequired
865
	 *
866
	 * @param int $id
867
	 * @return \OC\OCS\Result
868
	 */
869
	public function declineShare($id) {
870
		return $this->updateShareState($id, \OCP\Share::STATE_REJECTED);
871
	}
872
873
	/**
874
	 * @param $id
875
	 * @param $state
876
	 * @return \OC\OCS\Result
877
	 */
878
	private function updateShareState($id, $state) {
879
		$eventName = '';
880
		if ($state === \OCP\Share::STATE_ACCEPTED) {
881
			$eventName = 'accept';
882
		} elseif ($state === \OCP\Share::STATE_REJECTED) {
883
			$eventName = 'reject';
884
		}
885
886
		if (!$this->shareManager->shareApiEnabled()) {
887
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
888
		}
889
890
		try {
891
			$share = $this->getShareById($id, $this->currentUser->getUID());
892
			$this->eventDispatcher->dispatch('share.before' . $eventName, new GenericEvent(null, ['share' => $share]));
893
		} catch (ShareNotFound $e) {
894
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
895
		}
896
897
		$node = $share->getNode();
898
		$node->lock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
899
900
		// this checks that we are either the owner or recipient
901 View Code Duplication
		if (!$this->canAccessShare($share)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
902
			$node->unlock(ILockingProvider::LOCK_SHARED);
903
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
904
		}
905
906
		// only recipient can accept/reject share
907
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
908
			$share->getSharedBy() === $this->currentUser->getUID()) {
909
			$node->unlock(ILockingProvider::LOCK_SHARED);
910
			return new \OC\OCS\Result(null, 403, $this->l->t('Only recipient can change accepted state'));
911
		}
912
913
		if ($share->getState() === $state) {
914 View Code Duplication
			if ($eventName !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
915
				$this->eventDispatcher->dispatch('share.after' . $eventName, new GenericEvent(null, ['share' => $share]));
916
			}
917
			// if there are no changes in the state, just return the share as if the change was successful
918
			$node->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
919
			return new \OC\OCS\Result([$this->formatShare($share, true)]);
920
		}
921
922
		// we actually want to update all shares related to the node in case there are multiple
923
		// incoming shares for the same node (ex: receiving simultaneously through group share and user share)
924
		$allShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
925
		$allShares = \array_merge($allShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0));
926
927
		// resolve and deduplicate target if accepting
928
		if ($state === \OCP\Share::STATE_ACCEPTED) {
929
			$share = $this->deduplicateShareTarget($share);
930
		}
931
932
		$share->setState($state);
933
934
		try {
935
			foreach ($allShares as $aShare) {
936
				$aShare->setState($share->getState());
937
				$aShare->setTarget($share->getTarget());
938
				$this->shareManager->updateShareForRecipient($aShare, $this->currentUser->getUID());
939
			}
940
		} catch (\Exception $e) {
941
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
942
			return new \OC\OCS\Result(null, 400, $e->getMessage());
943
		}
944
945
		$node->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
946
947
		// FIXME: needs public API!
948
		\OC\Files\Filesystem::tearDown();
949
		// FIXME: trigger mount for user to make sure the new node is mounted already
950
		// before formatShare resolves it
951
		$this->rootFolder->getUserFolder($this->currentUser->getUID());
952
953
		$this->notificationPublisher->discardNotificationForUser($share, $this->currentUser->getUID());
954
955 View Code Duplication
		if ($eventName !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
956
			$this->eventDispatcher->dispatch('share.after' . $eventName, new GenericEvent(null, ['share' => $share]));
957
		}
958
		return new \OC\OCS\Result([$this->formatShare($share, true)]);
959
	}
960
961
	/**
962
	 * Deduplicate the share target in the current user home folder,
963
	 * based on configured share folder
964
	 *
965
	 * @param IShare $share share target to deduplicate
966
	 * @return IShare same share with target updated if necessary
967
	 */
968
	private function deduplicateShareTarget(IShare $share) {
969
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
970
		$mountPoint = \basename($share->getTarget());
971
		$parentDir = \dirname($share->getTarget());
972
		if (!$userFolder->nodeExists($parentDir)) {
973
			$parentDir = Helper::getShareFolder();
974
			$pathAttempt = \OC\Files\Filesystem::normalizePath($parentDir . '/' . $share->getTarget());
975
		} else {
976
			$pathAttempt = \OC\Files\Filesystem::normalizePath($share->getTarget());
977
		}
978
979
		$pathinfo = \pathinfo($pathAttempt);
980
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
981
		$name = $pathinfo['filename'];
982
983
		$i = 2;
984
		while ($userFolder->nodeExists($pathAttempt)) {
985
			$pathAttempt = \OC\Files\Filesystem::normalizePath($parentDir . '/' . $name . ' ('.$i.')' . $ext);
986
			$i++;
987
		}
988
989
		$share->setTarget($pathAttempt);
990
991
		return $share;
992
	}
993
994
	/**
995
	 * @param \OCP\Share\IShare $share
996
	 * @return bool
997
	 */
998
	protected function canAccessShare(\OCP\Share\IShare $share) {
999
		// A file with permissions 0 can't be accessed by us,
1000
		// unless it's a rejected sub-group share in which case we want it visible to let the user accept it again
1001
		if ($share->getPermissions() === 0
1002
			&& !($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $share->getState() === \OCP\Share::STATE_REJECTED)) {
1003
			return false;
1004
		}
1005
1006
		// Owner of the file and the sharer of the file can always get share
1007
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
1008
			$share->getSharedBy() === $this->currentUser->getUID()
1009
		) {
1010
			return true;
1011
		}
1012
1013
		// If the share is shared with you (or a group you are a member of)
1014
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
1015
			$share->getSharedWith() === $this->currentUser->getUID()) {
1016
			return true;
1017
		}
1018
1019
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
1020
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1021
			if ($sharedWith !== null && $sharedWith->inGroup($this->currentUser)) {
1022
				return true;
1023
			}
1024
		}
1025
1026
		return false;
1027
	}
1028
1029
	/**
1030
	 * Make sure that the passed date is valid ISO 8601
1031
	 * So YYYY-MM-DD
1032
	 * If not throw an exception
1033
	 *
1034
	 * @param string $expireDate
1035
	 *
1036
	 * @throws \Exception
1037
	 * @return \DateTime
1038
	 */
1039
	private function parseDate($expireDate) {
1040
		try {
1041
			$date = new \DateTime($expireDate);
1042
		} catch (\Exception $e) {
1043
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1044
		}
1045
1046
		if ($date === false) {
1047
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1048
		}
1049
1050
		$date->setTime(0, 0, 0);
1051
1052
		return $date;
1053
	}
1054
1055
	/**
1056
	 * Since we have multiple providers but the OCS Share API v1 does
1057
	 * not support this we need to check all backends.
1058
	 *
1059
	 * @param string $id
1060
	 * @return \OCP\Share\IShare
1061
	 * @throws ShareNotFound
1062
	 */
1063
	private function getShareById($id, $recipient = null) {
1064
		$share = null;
1065
1066
		// First check if it is an internal share.
1067
		try {
1068
			$share = $this->shareManager->getShareById('ocinternal:'.$id, $recipient);
1069
		} catch (ShareNotFound $e) {
1070
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1071
				throw new ShareNotFound();
1072
			}
1073
1074
			$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $recipient);
1075
		}
1076
1077
		return $share;
1078
	}
1079
}
1080