Completed
Push — master ( 53eb0f...62e19d )
by Lukas
35:26 queued 21:10
created

Share20OCS::getSharedWithMe()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 4
nop 1
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Vincent Petry <[email protected]>
8
 *
9
 * @license AGPL-3.0
10
 *
11
 * This code is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License, version 3,
13
 * as published by the Free Software Foundation.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License, version 3,
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
22
 *
23
 */
24
namespace OCA\Files_Sharing\API;
25
26
use OCP\AppFramework\Http\DataResponse;
27
use OCP\AppFramework\OCS\OCSBadRequestException;
28
use OCP\AppFramework\OCS\OCSException;
29
use OCP\AppFramework\OCS\OCSForbiddenException;
30
use OCP\AppFramework\OCS\OCSNotFoundException;
31
use OCP\AppFramework\OCSController;
32
use OCP\Files\Node;
33
use OCP\Files\NotFoundException;
34
use OCP\IGroupManager;
35
use OCP\IL10N;
36
use OCP\IUserManager;
37
use OCP\IRequest;
38
use OCP\IURLGenerator;
39
use OCP\IUser;
40
use OCP\Files\IRootFolder;
41
use OCP\Lock\LockedException;
42
use OCP\Share\IManager;
43
use OCP\Share\Exceptions\ShareNotFound;
44
use OCP\Share\Exceptions\GenericShareException;
45
use OCP\Lock\ILockingProvider;
46
use OCP\Share\IShare;
47
48
/**
49
 * Class Share20OCS
50
 *
51
 * @package OCA\Files_Sharing\API
52
 */
53
class Share20OCS extends OCSController {
54
55
	/** @var IManager */
56
	private $shareManager;
57
	/** @var IGroupManager */
58
	private $groupManager;
59
	/** @var IUserManager */
60
	private $userManager;
61
	/** @var IRequest */
62
	protected $request;
63
	/** @var IRootFolder */
64
	private $rootFolder;
65
	/** @var IURLGenerator */
66
	private $urlGenerator;
67
	/** @var IUser */
68
	private $currentUser;
69
	/** @var IL10N */
70
	private $l;
71
	/** @var \OCP\Files\Node */
72
	private $lockedNode;
73
74
	/**
75
	 * Share20OCS constructor.
76
	 *
77
	 * @param string $appName
78
	 * @param IRequest $request
79
	 * @param IManager $shareManager
80
	 * @param IGroupManager $groupManager
81
	 * @param IUserManager $userManager
82
	 * @param IRootFolder $rootFolder
83
	 * @param IURLGenerator $urlGenerator
84
	 * @param IUser $currentUser
85
	 * @param IL10N $l10n
86
	 */
87 View Code Duplication
	public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
88
		$appName,
89
		IRequest $request,
90
		IManager $shareManager,
91
		IGroupManager $groupManager,
92
		IUserManager $userManager,
93
		IRootFolder $rootFolder,
94
		IURLGenerator $urlGenerator,
95
		IUser $currentUser,
96
		IL10N $l10n
97
	) {
98
		parent::__construct($appName, $request);
99
100
		$this->shareManager = $shareManager;
101
		$this->userManager = $userManager;
102
		$this->groupManager = $groupManager;
103
		$this->request = $request;
104
		$this->rootFolder = $rootFolder;
105
		$this->urlGenerator = $urlGenerator;
106
		$this->currentUser = $currentUser;
107
		$this->l = $l10n;
108
	}
109
110
	/**
111
	 * Convert an IShare to an array for OCS output
112
	 *
113
	 * @param \OCP\Share\IShare $share
114
	 * @param Node|null $recipientNode
115
	 * @return array
116
	 * @throws NotFoundException In case the node can't be resolved.
117
	 */
118
	protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null) {
119
		$sharedBy = $this->userManager->get($share->getSharedBy());
120
		$shareOwner = $this->userManager->get($share->getShareOwner());
121
122
		$result = [
123
			'id' => $share->getId(),
124
			'share_type' => $share->getShareType(),
125
			'uid_owner' => $share->getSharedBy(),
126
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
127
			'permissions' => $share->getPermissions(),
128
			'stime' => $share->getShareTime()->getTimestamp(),
129
			'parent' => null,
130
			'expiration' => null,
131
			'token' => null,
132
			'uid_file_owner' => $share->getShareOwner(),
133
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
134
		];
135
136
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
137
		if ($recipientNode) {
138
			$node = $recipientNode;
139
		} else {
140
			$nodes = $userFolder->getById($share->getNodeId());
141
142
			if (empty($nodes)) {
143
				// fallback to guessing the path
144
				$node = $userFolder->get($share->getTarget());
145
				if ($node === null) {
146
					throw new NotFoundException();
147
				}
148
			} else {
149
				$node = $nodes[0];
150
			}
151
		}
152
153
		$result['path'] = $userFolder->getRelativePath($node->getPath());
154
		if ($node instanceOf \OCP\Files\Folder) {
155
			$result['item_type'] = 'folder';
156
		} else {
157
			$result['item_type'] = 'file';
158
		}
159
		$result['mimetype'] = $node->getMimetype();
160
		$result['storage_id'] = $node->getStorage()->getId();
161
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
162
		$result['item_source'] = $node->getId();
163
		$result['file_source'] = $node->getId();
164
		$result['file_parent'] = $node->getParent()->getId();
165
		$result['file_target'] = $share->getTarget();
166
167
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
168
			$sharedWith = $this->userManager->get($share->getSharedWith());
169
			$result['share_with'] = $share->getSharedWith();
170
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
171
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
172
			$result['share_with'] = $share->getSharedWith();
173
			$result['share_with_displayname'] = $share->getSharedWith();
174
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
175
176
			$result['share_with'] = $share->getPassword();
177
			$result['share_with_displayname'] = $share->getPassword();
178
179
			$result['token'] = $share->getToken();
180
			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
181
182
			$expiration = $share->getExpirationDate();
183
			if ($expiration !== null) {
184
				$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
185
			}
186
187
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
188
			$result['share_with'] = $share->getSharedWith();
189
			$result['share_with_displayname'] = $share->getSharedWith();
190
			$result['token'] = $share->getToken();
191
		}
192
193
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
194
195
		return $result;
196
	}
197
198
	/**
199
	 * Get a specific share by id
200
	 *
201
	 * @NoAdminRequired
202
	 *
203
	 * @param string $id
204
	 * @return DataResponse
205
	 * @throws OCSNotFoundException
206
	 */
207
	public function getShare($id) {
208
		try {
209
			$share = $this->getShareById($id);
210
		} catch (ShareNotFound $e) {
211
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
212
		}
213
214
		if ($this->canAccessShare($share)) {
215
			try {
216
				$share = $this->formatShare($share);
217
				return new DataResponse([$share]);
218
			} catch (NotFoundException $e) {
219
				//Fall trough
220
			}
221
		}
222
223
		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
224
	}
225
226
	/**
227
	 * Delete a share
228
	 *
229
	 * @NoAdminRequired
230
	 *
231
	 * @param string $id
232
	 * @return DataResponse
233
	 * @throws OCSNotFoundException
234
	 */
235
	public function deleteShare($id) {
236
		try {
237
			$share = $this->getShareById($id);
238
		} catch (ShareNotFound $e) {
239
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
240
		}
241
242
		try {
243
			$this->lock($share->getNode());
244
		} catch (LockedException $e) {
245
			throw new OCSNotFoundException($this->l->t('could not delete share'));
246
		}
247
248
		if (!$this->canAccessShare($share, false)) {
249
			throw new OCSNotFoundException($this->l->t('Could not delete share'));
250
		}
251
252
		$this->shareManager->deleteShare($share);
253
254
		return new DataResponse();
255
	}
256
257
	/**
258
	 * @NoAdminRequired
259
	 *
260
	 * @param string $path
261
	 * @param int $permissions
262
	 * @param int $shareType
263
	 * @param string $shareWith
264
	 * @param string $publicUpload
265
	 * @param string $password
266
	 * @param string $expireDate
267
	 *
268
	 * @return DataResponse
269
	 * @throws OCSNotFoundException
270
	 * @throws OCSForbiddenException
271
	 * @throws OCSBadRequestException
272
	 * @throws OCSException
273
	 */
274
	public function createShare(
275
		$path = null,
276
		$permissions = \OCP\Constants::PERMISSION_ALL,
277
		$shareType = -1,
278
		$shareWith = null,
279
		$publicUpload = 'false',
280
		$password = '',
281
		$expireDate = ''
282
	) {
283
		$share = $this->shareManager->newShare();
284
285
		// Verify path
286
		if ($path === null) {
287
			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
288
		}
289
290
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
291
		try {
292
			$path = $userFolder->get($path);
293
		} catch (NotFoundException $e) {
294
			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
295
		}
296
297
		$share->setNode($path);
298
299
		try {
300
			$this->lock($share->getNode());
301
		} catch (LockedException $e) {
302
			throw new OCSNotFoundException($this->l->t('Could not create share'));
303
		}
304
305
		if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
306
			throw new OCSNotFoundException($this->l->t('invalid permissions'));
307
		}
308
309
		// Shares always require read permissions
310
		$permissions |= \OCP\Constants::PERMISSION_READ;
311
312
		if ($path instanceof \OCP\Files\File) {
313
			// Single file shares should never have delete or create permissions
314
			$permissions &= ~\OCP\Constants::PERMISSION_DELETE;
315
			$permissions &= ~\OCP\Constants::PERMISSION_CREATE;
316
		}
317
318
		/*
319
		 * Hack for https://github.com/owncloud/core/issues/22587
320
		 * We check the permissions via webdav. But the permissions of the mount point
321
		 * do not equal the share permissions. Here we fix that for federated mounts.
322
		 */
323
		if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
324
			$permissions &= ~($permissions & ~$path->getPermissions());
325
		}
326
327
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
328
			// Valid user is required to share
329
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
330
				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
331
			}
332
			$share->setSharedWith($shareWith);
333
			$share->setPermissions($permissions);
334
		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
335
			if (!$this->shareManager->allowGroupSharing()) {
336
				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
337
			}
338
339
			// Valid group is required to share
340
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
341
				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
342
			}
343
			$share->setSharedWith($shareWith);
344
			$share->setPermissions($permissions);
345
		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
346
			//Can we even share links?
347
			if (!$this->shareManager->shareApiAllowLinks()) {
348
				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
349
			}
350
351
			/*
352
			 * For now we only allow 1 link share.
353
			 * Return the existing link share if this is a duplicate
354
			 */
355
			$existingShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
356
			if (!empty($existingShares)) {
357
				return new DataResponse($this->formatShare($existingShares[0]));
358
			}
359
360
			if ($publicUpload === 'true') {
361
				// Check if public upload is allowed
362
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
363
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
364
				}
365
366
				// Public upload can only be set for folders
367
				if ($path instanceof \OCP\Files\File) {
368
					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
369
				}
370
371
				$share->setPermissions(
372
					\OCP\Constants::PERMISSION_READ |
373
					\OCP\Constants::PERMISSION_CREATE |
374
					\OCP\Constants::PERMISSION_UPDATE |
375
					\OCP\Constants::PERMISSION_DELETE
376
				);
377
			} else {
378
				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
379
			}
380
381
			// Set password
382
			if ($password !== '') {
383
				$share->setPassword($password);
384
			}
385
386
			//Expire date
387
			if ($expireDate !== '') {
388
				try {
389
					$expireDate = $this->parseDate($expireDate);
390
					$share->setExpirationDate($expireDate);
391
				} catch (\Exception $e) {
392
					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
393
				}
394
			}
395
396
		} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
397
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
398
				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
399
			}
400
401
			$share->setSharedWith($shareWith);
402
			$share->setPermissions($permissions);
403
		} else {
404
			throw new OCSBadRequestException($this->l->t('Unknown share type'));
405
		}
406
407
		$share->setShareType($shareType);
408
		$share->setSharedBy($this->currentUser->getUID());
409
410
		try {
411
			$share = $this->shareManager->createShare($share);
412
		} catch (GenericShareException $e) {
413
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
414
			throw new OCSException($e->getHint(), $code);
415
		} catch (\Exception $e) {
416
			throw new OCSForbiddenException($e->getMessage());
417
		}
418
419
		$output = $this->formatShare($share);
420
421
		return new DataResponse($output);
422
	}
423
424
	/**
425
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
426
	 * @return DataResponse
427
	 */
428
	private function getSharedWithMe($node = null) {
429
		$userShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
430
		$groupShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
431
432
		$shares = array_merge($userShares, $groupShares);
433
434
		$shares = array_filter($shares, function (IShare $share) {
435
			return $share->getShareOwner() !== $this->currentUser->getUID();
436
		});
437
438
		$formatted = [];
439
		foreach ($shares as $share) {
440
			if ($this->canAccessShare($share)) {
441
				try {
442
					$formatted[] = $this->formatShare($share);
443
				} catch (NotFoundException $e) {
444
					// Ignore this share
445
				}
446
			}
447
		}
448
449
		return new DataResponse($formatted);
450
	}
451
452
	/**
453
	 * @param \OCP\Files\Folder $folder
454
	 * @return DataResponse
455
	 * @throws OCSBadRequestException
456
	 */
457
	private function getSharesInDir($folder) {
458
		if (!($folder instanceof \OCP\Files\Folder)) {
459
			throw new OCSBadRequestException($this->l->t('Not a directory'));
460
		}
461
462
		$nodes = $folder->getDirectoryListing();
463
		/** @var \OCP\Share\IShare[] $shares */
464
		$shares = [];
465
		foreach ($nodes as $node) {
466
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
467
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
468
			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
469
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
470
				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
471
			}
472
		}
473
474
		$formatted = [];
475
		foreach ($shares as $share) {
476
			try {
477
				$formatted[] = $this->formatShare($share);
478
			} catch (NotFoundException $e) {
479
				//Ignore this share
480
			}
481
		}
482
483
		return new DataResponse($formatted);
484
	}
485
486
	/**
487
	 * The getShares function.
488
	 *
489
	 * @NoAdminRequired
490
	 *
491
	 * @param string $shared_with_me
492
	 * @param string $reshares
493
	 * @param string $subfiles
494
	 * @param string $path
495
	 *
496
	 * - Get shares by the current user
497
	 * - Get shares by the current user and reshares (?reshares=true)
498
	 * - Get shares with the current user (?shared_with_me=true)
499
	 * - Get shares for a specific path (?path=...)
500
	 * - Get all shares in a folder (?subfiles=true&path=..)
501
	 *
502
	 * @return DataResponse
503
	 * @throws OCSNotFoundException
504
	 */
505
	public function getShares(
506
		$shared_with_me = 'false',
507
		$reshares = 'false',
508
		$subfiles = 'false',
509
		$path = null
510
	) {
511
512
		if ($path !== null) {
513
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
514
			try {
515
				$path = $userFolder->get($path);
516
				$this->lock($path);
517
			} catch (\OCP\Files\NotFoundException $e) {
518
				throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
519
			} catch (LockedException $e) {
520
				throw new OCSNotFoundException($this->l->t('Could not lock path'));
521
			}
522
		}
523
524
		if ($shared_with_me === 'true') {
525
			$result = $this->getSharedWithMe($path);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCA\Files_Sharing\API\Sh...0OCS::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...
526
			return $result;
527
		}
528
529
		if ($subfiles === 'true') {
530
			$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...
531
			return $result;
532
		}
533
534
		if ($reshares === 'true') {
535
			$reshares = true;
536
		} else {
537
			$reshares = false;
538
		}
539
540
		// Get all shares
541
		$userShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
542
		$groupShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
543
		$linkShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
544
		$shares = array_merge($userShares, $groupShares, $linkShares);
545
546
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
547
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
548
			$shares = array_merge($shares, $federatedShares);
549
		}
550
551
		$formatted = [];
552
		foreach ($shares as $share) {
553
			try {
554
				$formatted[] = $this->formatShare($share, $path);
555
			} catch (NotFoundException $e) {
556
				//Ignore share
557
			}
558
		}
559
560
		return new DataResponse($formatted);
561
	}
562
563
	/**
564
	 * @NoAdminRequired
565
	 *
566
	 * @param int $id
567
	 * @param int $permissions
568
	 * @param string $password
569
	 * @param string $publicUpload
570
	 * @param string $expireDate
571
	 * @return DataResponse
572
	 * @throws OCSNotFoundException
573
	 * @throws OCSBadRequestException
574
	 * @throws OCSForbiddenException
575
	 */
576
	public function updateShare(
577
		$id,
578
		$permissions = null,
579
		$password = null,
580
		$publicUpload = null,
581
		$expireDate = null
582
	) {
583
		try {
584
			$share = $this->getShareById($id);
585
		} catch (ShareNotFound $e) {
586
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
587
		}
588
589
		$this->lock($share->getNode());
590
591
		if (!$this->canAccessShare($share, false)) {
592
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
593
		}
594
595
		/*
596
		 * expirationdate, password and publicUpload only make sense for link shares
597
		 */
598
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
599
			if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) {
600
				throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
601
			}
602
603
			$newPermissions = null;
604
			if ($publicUpload === 'true') {
605
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
606
			} else if ($publicUpload === 'false') {
607
				$newPermissions = \OCP\Constants::PERMISSION_READ;
608
			}
609
610
			if ($permissions !== null) {
611
				$newPermissions = (int)$permissions;
612
			}
613
614
			if ($newPermissions !== null &&
615
				!in_array($newPermissions, [
616
					\OCP\Constants::PERMISSION_READ,
617
					\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE, // legacy
618
					\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE, // correct
619
					\OCP\Constants::PERMISSION_CREATE, // hidden file list
620
				])
621
			) {
622
				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
623
			}
624
625
			if (
626
				// legacy
627
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) ||
628
				// correct
629
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
630
			) {
631
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
632
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
633
				}
634
635
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
636
					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
637
				}
638
639
				// normalize to correct public upload permissions
640
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
641
			}
642
643
			if ($newPermissions !== null) {
644
				$share->setPermissions($newPermissions);
645
			}
646
647
			if ($expireDate === '') {
648
				$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...
649
			} else if ($expireDate !== null) {
650
				try {
651
					$expireDate = $this->parseDate($expireDate);
652
				} catch (\Exception $e) {
653
					throw new OCSBadRequestException($e->getMessage());
654
				}
655
				$share->setExpirationDate($expireDate);
656
			}
657
658
			if ($password === '') {
659
				$share->setPassword(null);
660
			} else if ($password !== null) {
661
				$share->setPassword($password);
662
			}
663
664
		} else {
665
			// For other shares only permissions is valid.
666
			if ($permissions === null) {
667
				throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
668
			} else {
669
				$permissions = (int)$permissions;
670
				$share->setPermissions($permissions);
671
			}
672
		}
673
674
		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser->getUID()) {
675
			/* Check if this is an incomming share */
676
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
677
			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
678
679
			/** @var \OCP\Share\IShare[] $incomingShares */
680
			if (!empty($incomingShares)) {
681
				$maxPermissions = 0;
682
				foreach ($incomingShares as $incomingShare) {
683
					$maxPermissions |= $incomingShare->getPermissions();
684
				}
685
686
				if ($share->getPermissions() & ~$maxPermissions) {
687
					throw new OCSNotFoundException($this->l->t('Cannot increase permissions'));
688
				}
689
			}
690
		}
691
692
693
		try {
694
			$share = $this->shareManager->updateShare($share);
695
		} catch (\Exception $e) {
696
			throw new OCSBadRequestException($e->getMessage());
697
		}
698
699
		return new DataResponse($this->formatShare($share));
700
	}
701
702
	/**
703
	 * @param \OCP\Share\IShare $share
704
	 * @return bool
705
	 */
706
	protected function canAccessShare(\OCP\Share\IShare $share, $checkGroups = true) {
707
		// A file with permissions 0 can't be accessed by us. So Don't show it
708
		if ($share->getPermissions() === 0) {
709
			return false;
710
		}
711
712
		// Owner of the file and the sharer of the file can always get share
713
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
714
			$share->getSharedBy() === $this->currentUser->getUID()
715
		) {
716
			return true;
717
		}
718
719
		// If the share is shared with you (or a group you are a member of)
720
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
721
			$share->getSharedWith() === $this->currentUser->getUID()
722
		) {
723
			return true;
724
		}
725
726
		if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
727
			$sharedWith = $this->groupManager->get($share->getSharedWith());
728
			if ($sharedWith->inGroup($this->currentUser)) {
729
				return true;
730
			}
731
		}
732
733
		return false;
734
	}
735
736
	/**
737
	 * Make sure that the passed date is valid ISO 8601
738
	 * So YYYY-MM-DD
739
	 * If not throw an exception
740
	 *
741
	 * @param string $expireDate
742
	 *
743
	 * @throws \Exception
744
	 * @return \DateTime
745
	 */
746
	private function parseDate($expireDate) {
747
		try {
748
			$date = new \DateTime($expireDate);
749
		} catch (\Exception $e) {
750
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
751
		}
752
753
		if ($date === false) {
754
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
755
		}
756
757
		$date->setTime(0, 0, 0);
758
759
		return $date;
760
	}
761
762
	/**
763
	 * Since we have multiple providers but the OCS Share API v1 does
764
	 * not support this we need to check all backends.
765
	 *
766
	 * @param string $id
767
	 * @return \OCP\Share\IShare
768
	 * @throws ShareNotFound
769
	 */
770
	private function getShareById($id) {
771
		$share = null;
772
773
		// First check if it is an internal share.
774
		try {
775
			$share = $this->shareManager->getShareById('ocinternal:' . $id);
776
		} catch (ShareNotFound $e) {
777
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
778
				throw new ShareNotFound();
779
			}
780
781
			$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
782
		}
783
784
		return $share;
785
	}
786
787
	/**
788
	 * Lock a Node
789
	 *
790
	 * @param \OCP\Files\Node $node
791
	 */
792
	private function lock(\OCP\Files\Node $node) {
793
		$node->lock(ILockingProvider::LOCK_SHARED);
794
		$this->lockedNode = $node;
795
	}
796
797
	/**
798
	 * Cleanup the remaining locks
799
	 */
800
	public function cleanup() {
801
		if ($this->lockedNode !== null) {
802
			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
803
		}
804
	}
805
}
806