Passed
Push — master ( 2b19da...9cd7ec )
by John
11:47 queued 11s
created

ShareAPIController::getFormattedShares()   C

Complexity

Conditions 12
Paths 50

Size

Total Lines 54
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 54
rs 6.9666
cc 12
nc 50
nop 6

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Maxence Lange <[email protected]>
10
 * @author Michael Jobst <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 * @author John Molakvoæ <[email protected]>
15
 * @author Maxence Lange <[email protected]>
16
 *
17
 * @license AGPL-3.0
18
 *
19
 * This code is free software: you can redistribute it and/or modify
20
 * it under the terms of the GNU Affero General Public License, version 3,
21
 * as published by the Free Software Foundation.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License, version 3,
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
30
 *
31
 */
32
33
namespace OCA\Files_Sharing\Controller;
34
35
use OCA\Files_Sharing\Exceptions\SharingRightsException;
36
use OCA\Files_Sharing\External\Storage;
37
use OCA\Files\Helper;
38
use OCP\App\IAppManager;
39
use OCP\AppFramework\Http\DataResponse;
40
use OCP\AppFramework\OCS\OCSBadRequestException;
41
use OCP\AppFramework\OCS\OCSException;
42
use OCP\AppFramework\OCS\OCSForbiddenException;
43
use OCP\AppFramework\OCS\OCSNotFoundException;
44
use OCP\AppFramework\OCSController;
45
use OCP\AppFramework\QueryException;
46
use OCP\Constants;
47
use OCP\Files\InvalidPathException;
48
use OCP\Files\IRootFolder;
49
use OCP\Files\Node;
50
use OCP\Files\NotFoundException;
51
use OCP\IConfig;
52
use OCP\IGroupManager;
53
use OCP\IL10N;
54
use OCP\IRequest;
55
use OCP\IServerContainer;
56
use OCP\IURLGenerator;
57
use OCP\IUserManager;
58
use OCP\Lock\ILockingProvider;
59
use OCP\Lock\LockedException;
60
use OCP\Share;
61
use OCP\Share\Exceptions\GenericShareException;
62
use OCP\Share\Exceptions\ShareNotFound;
63
use OCP\Share\IManager;
64
use OCP\Share\IShare;
65
66
/**
67
 * Class Share20OCS
68
 *
69
 * @package OCA\Files_Sharing\API
70
 */
71
class ShareAPIController extends OCSController {
72
73
	/** @var IManager */
74
	private $shareManager;
75
	/** @var IGroupManager */
76
	private $groupManager;
77
	/** @var IUserManager */
78
	private $userManager;
79
	/** @var IRootFolder */
80
	private $rootFolder;
81
	/** @var IURLGenerator */
82
	private $urlGenerator;
83
	/** @var string */
84
	private $currentUser;
85
	/** @var IL10N */
86
	private $l;
87
	/** @var \OCP\Files\Node */
88
	private $lockedNode;
89
	/** @var IConfig */
90
	private $config;
91
	/** @var IAppManager */
92
	private $appManager;
93
	/** @var IServerContainer */
94
	private $serverContainer;
95
96
	/**
97
	 * Share20OCS constructor.
98
	 *
99
	 * @param string $appName
100
	 * @param IRequest $request
101
	 * @param IManager $shareManager
102
	 * @param IGroupManager $groupManager
103
	 * @param IUserManager $userManager
104
	 * @param IRootFolder $rootFolder
105
	 * @param IURLGenerator $urlGenerator
106
	 * @param string $userId
107
	 * @param IL10N $l10n
108
	 * @param IConfig $config
109
	 * @param IAppManager $appManager
110
	 * @param IServerContainer $serverContainer
111
	 */
112
	public function __construct(
113
		string $appName,
114
		IRequest $request,
115
		IManager $shareManager,
116
		IGroupManager $groupManager,
117
		IUserManager $userManager,
118
		IRootFolder $rootFolder,
119
		IURLGenerator $urlGenerator,
120
		string $userId = null,
121
		IL10N $l10n,
122
		IConfig $config,
123
		IAppManager $appManager,
124
		IServerContainer $serverContainer
125
	) {
126
		parent::__construct($appName, $request);
127
128
		$this->shareManager = $shareManager;
129
		$this->userManager = $userManager;
130
		$this->groupManager = $groupManager;
131
		$this->request = $request;
132
		$this->rootFolder = $rootFolder;
133
		$this->urlGenerator = $urlGenerator;
134
		$this->currentUser = $userId;
135
		$this->l = $l10n;
136
		$this->config = $config;
137
		$this->appManager = $appManager;
138
		$this->serverContainer = $serverContainer;
139
	}
140
141
	/**
142
	 * Convert an IShare to an array for OCS output
143
	 *
144
	 * @param \OCP\Share\IShare $share
145
	 * @param Node|null $recipientNode
146
	 * @return array
147
	 * @throws NotFoundException In case the node can't be resolved.
148
	 *
149
	 * @suppress PhanUndeclaredClassMethod
150
	 */
151
	protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array {
152
		$sharedBy = $this->userManager->get($share->getSharedBy());
153
		$shareOwner = $this->userManager->get($share->getShareOwner());
154
155
		$result = [
156
			'id' => $share->getId(),
157
			'share_type' => $share->getShareType(),
158
			'uid_owner' => $share->getSharedBy(),
159
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
160
			// recipient permissions
161
			'permissions' => $share->getPermissions(),
162
			// current user permissions on this share
163
			'can_edit' => $this->canEditShare($share),
164
			'can_delete' => $this->canDeleteShare($share),
165
			'stime' => $share->getShareTime()->getTimestamp(),
166
			'parent' => null,
167
			'expiration' => null,
168
			'token' => null,
169
			'uid_file_owner' => $share->getShareOwner(),
170
			'note' => $share->getNote(),
171
			'label' => $share->getLabel(),
172
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
173
		];
174
175
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
176
		if ($recipientNode) {
177
			$node = $recipientNode;
178
		} else {
179
			$nodes = $userFolder->getById($share->getNodeId());
180
			if (empty($nodes)) {
181
				// fallback to guessing the path
182
				$node = $userFolder->get($share->getTarget());
183
				if ($node === null || $share->getTarget() === '') {
184
					throw new NotFoundException();
185
				}
186
			} else {
187
				$node = reset($nodes);
188
			}
189
		}
190
191
		$result['path'] = $userFolder->getRelativePath($node->getPath());
192
		if ($node instanceof \OCP\Files\Folder) {
193
			$result['item_type'] = 'folder';
194
		} else {
195
			$result['item_type'] = 'file';
196
		}
197
198
		$result['mimetype'] = $node->getMimetype();
199
		$result['storage_id'] = $node->getStorage()->getId();
200
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
201
		$result['item_source'] = $node->getId();
202
		$result['file_source'] = $node->getId();
203
		$result['file_parent'] = $node->getParent()->getId();
204
		$result['file_target'] = $share->getTarget();
205
206
		$expiration = $share->getExpirationDate();
207
		if ($expiration !== null) {
208
			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
209
		}
210
211
		if ($share->getShareType() === Share::SHARE_TYPE_USER) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

211
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
212
			$sharedWith = $this->userManager->get($share->getSharedWith());
213
			$result['share_with'] = $share->getSharedWith();
214
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
215
		} else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

215
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
216
			$group = $this->groupManager->get($share->getSharedWith());
217
			$result['share_with'] = $share->getSharedWith();
218
			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
219
		} else if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

219
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
220
221
			// "share_with" and "share_with_displayname" for passwords of link
222
			// shares was deprecated in Nextcloud 15, use "password" instead.
223
			$result['share_with'] = $share->getPassword();
224
			$result['share_with_displayname'] = $share->getPassword();
225
226
			$result['password'] = $share->getPassword();
227
228
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
229
230
			$result['token'] = $share->getToken();
231
			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
232
		} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE_GROUP has been deprecated: 17.0.0 - use IShare::REMOTE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
		} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE has been deprecated: 17.0.0 - use IShare::TYPE_REMOTE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
233
			$result['share_with'] = $share->getSharedWith();
234
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
235
			$result['token'] = $share->getToken();
236
		} else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

236
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
237
			$result['share_with'] = $share->getSharedWith();
238
			$result['password'] = $share->getPassword();
239
			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
240
			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
241
			$result['token'] = $share->getToken();
242
		} else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

242
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
243
			// getSharedWith() returns either "name (type, owner)" or
244
			// "name (type, owner) [id]", depending on the Circles app version.
245
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
246
247
			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
248
			if (empty($result['share_with_displayname'])) {
249
				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
250
				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
251
			}
252
253
			$result['share_with_avatar'] = $share->getSharedWithAvatar();
254
255
			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
256
			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
257
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
258
				$shareWithLength = -1;
259
			}
260
			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
261
		} else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

261
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
262
			$result['share_with'] = $share->getSharedWith();
263
			$result['share_with_displayname'] = '';
264
265
			try {
266
				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
267
			} catch (QueryException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
268
		}
269
270
271
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
272
		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
273
274
		return $result;
275
	}
276
277
	/**
278
	 * Check if one of the users address books knows the exact property, if
279
	 * yes we return the full name.
280
	 *
281
	 * @param string $query
282
	 * @param string $property
283
	 * @return string
284
	 */
285
	private function getDisplayNameFromAddressBook(string $query, string $property): string {
286
		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
287
		$result = \OC::$server->getContactsManager()->search($query, [$property]);
288
		foreach ($result as $r) {
289
			foreach ($r[$property] as $value) {
290
				if ($value === $query) {
291
					return $r['FN'];
292
				}
293
			}
294
		}
295
296
		return $query;
297
	}
298
299
	/**
300
	 * Get a specific share by id
301
	 *
302
	 * @NoAdminRequired
303
	 *
304
	 * @param string $id
305
	 * @return DataResponse
306
	 * @throws OCSNotFoundException
307
	 */
308
	public function getShare(string $id): DataResponse {
309
		try {
310
			$share = $this->getShareById($id);
311
		} catch (ShareNotFound $e) {
312
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
313
		}
314
315
		try {
316
			if ($this->canAccessShare($share)) {
317
				$share = $this->formatShare($share);
318
				return new DataResponse([$share]);
319
			}
320
		} catch (NotFoundException $e) {
321
			// Fall trough
322
		}
323
324
		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
325
	}
326
327
	/**
328
	 * Delete a share
329
	 *
330
	 * @NoAdminRequired
331
	 *
332
	 * @param string $id
333
	 * @return DataResponse
334
	 * @throws OCSNotFoundException
335
	 */
336
	public function deleteShare(string $id): DataResponse {
337
		try {
338
			$share = $this->getShareById($id);
339
		} catch (ShareNotFound $e) {
340
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
341
		}
342
343
		try {
344
			$this->lock($share->getNode());
345
		} catch (LockedException $e) {
346
			throw new OCSNotFoundException($this->l->t('Could not delete share'));
347
		}
348
349
		if (!$this->canAccessShare($share)) {
350
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
351
		}
352
353
		// if it's a group share or a room share
354
		// we don't delete the share, but only the
355
		// mount point. Allowing it to be restored
356
		// from the deleted shares
357
		if ($this->canDeleteShareFromSelf($share)) {
358
			$this->shareManager->deleteFromSelf($share, $this->currentUser);
359
		} else {
360
			if (!$this->canDeleteShare($share)) {
361
				throw new OCSForbiddenException($this->l->t('Could not delete share'));
362
			}
363
364
			$this->shareManager->deleteShare($share);
365
		}
366
367
		return new DataResponse();
368
	}
369
370
	/**
371
	 * @NoAdminRequired
372
	 *
373
	 * @param string $path
374
	 * @param int $permissions
375
	 * @param int $shareType
376
	 * @param string $shareWith
377
	 * @param string $publicUpload
378
	 * @param string $password
379
	 * @param string $sendPasswordByTalk
380
	 * @param string $expireDate
381
	 * @param string $label
382
	 *
383
	 * @return DataResponse
384
	 * @throws NotFoundException
385
	 * @throws OCSBadRequestException
386
	 * @throws OCSException
387
	 * @throws OCSForbiddenException
388
	 * @throws OCSNotFoundException
389
	 * @throws InvalidPathException
390
	 * @suppress PhanUndeclaredClassMethod
391
	 */
392
	public function createShare(
393
		string $path = null,
394
		int $permissions = null,
395
		int $shareType = -1,
396
		string $shareWith = null,
397
		string $publicUpload = 'false',
398
		string $password = '',
399
		string $sendPasswordByTalk = null,
400
		string $expireDate = '',
401
		string $label = ''
402
	): DataResponse {
403
		$share = $this->shareManager->newShare();
404
405
		if ($permissions === null) {
406
			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
407
		}
408
409
		// Verify path
410
		if ($path === null) {
411
			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
412
		}
413
414
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
415
		try {
416
			$path = $userFolder->get($path);
417
		} catch (NotFoundException $e) {
418
			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
419
		}
420
421
		$share->setNode($path);
422
423
		try {
424
			$this->lock($share->getNode());
425
		} catch (LockedException $e) {
426
			throw new OCSNotFoundException($this->l->t('Could not create share'));
427
		}
428
429
		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
430
			throw new OCSNotFoundException($this->l->t('invalid permissions'));
431
		}
432
433
		// Shares always require read permissions
434
		$permissions |= Constants::PERMISSION_READ;
435
436
		if ($path instanceof \OCP\Files\File) {
437
			// Single file shares should never have delete or create permissions
438
			$permissions &= ~Constants::PERMISSION_DELETE;
439
			$permissions &= ~Constants::PERMISSION_CREATE;
440
		}
441
442
		/**
443
		 * Hack for https://github.com/owncloud/core/issues/22587
444
		 * We check the permissions via webdav. But the permissions of the mount point
445
		 * do not equal the share permissions. Here we fix that for federated mounts.
446
		 */
447
		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
448
			$permissions &= ~($permissions & ~$path->getPermissions());
449
		}
450
451
		if ($shareType === Share::SHARE_TYPE_USER) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

451
		if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
452
			// Valid user is required to share
453
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
454
				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
455
			}
456
			$share->setSharedWith($shareWith);
457
			$share->setPermissions($permissions);
458
		} else if ($shareType === Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

458
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
459
			if (!$this->shareManager->allowGroupSharing()) {
460
				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
461
			}
462
463
			// Valid group is required to share
464
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
465
				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
466
			}
467
			$share->setSharedWith($shareWith);
468
			$share->setPermissions($permissions);
469
		} else if ($shareType === Share::SHARE_TYPE_LINK
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

469
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
470
			|| $shareType === Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

470
			|| $shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
471
472
			// Can we even share links?
473
			if (!$this->shareManager->shareApiAllowLinks()) {
474
				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
475
			}
476
477
			if ($publicUpload === 'true') {
478
				// Check if public upload is allowed
479
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
480
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
481
				}
482
483
				// Public upload can only be set for folders
484
				if ($path instanceof \OCP\Files\File) {
485
					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
486
				}
487
488
				$share->setPermissions(
489
					Constants::PERMISSION_READ |
490
					Constants::PERMISSION_CREATE |
491
					Constants::PERMISSION_UPDATE |
492
					Constants::PERMISSION_DELETE
493
				);
494
			} else {
495
				$share->setPermissions(Constants::PERMISSION_READ);
496
			}
497
498
			// Set password
499
			if ($password !== '') {
500
				$share->setPassword($password);
501
			}
502
503
			// Only share by mail have a recipient
504
			if ($shareType === Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

504
			if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
505
				$share->setSharedWith($shareWith);
506
			} else {
507
				// Only link share have a label
508
				if (!empty($label)) {
509
					$share->setLabel($label);
510
				}
511
			}
512
513
			if ($sendPasswordByTalk === 'true') {
514
				if (!$this->appManager->isEnabledForUser('spreed')) {
515
					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
516
				}
517
518
				$share->setSendPasswordByTalk(true);
519
			}
520
521
			//Expire date
522
			if ($expireDate !== '') {
523
				try {
524
					$expireDate = $this->parseDate($expireDate);
525
					$share->setExpirationDate($expireDate);
526
				} catch (\Exception $e) {
527
					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
528
				}
529
			}
530
		} else if ($shareType === Share::SHARE_TYPE_REMOTE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE has been deprecated: 17.0.0 - use IShare::TYPE_REMOTE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

530
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
531
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
532
				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]));
533
			}
534
535
			$share->setSharedWith($shareWith);
536
			$share->setPermissions($permissions);
537
		} else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE_GROUP has been deprecated: 17.0.0 - use IShare::REMOTE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

537
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
538
			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
539
				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]));
540
			}
541
542
			$share->setSharedWith($shareWith);
543
			$share->setPermissions($permissions);
544
		} else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

544
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
545
			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
546
				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
547
			}
548
549
			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
0 ignored issues
show
Bug introduced by
The type OCA\Circles\Api\v1\Circles was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
550
551
			// Valid circle is required to share
552
			if ($circle === null) {
553
				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
554
			}
555
			$share->setSharedWith($shareWith);
556
			$share->setPermissions($permissions);
557
		} else if ($shareType === Share::SHARE_TYPE_ROOM) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

557
		} else if ($shareType === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
558
			try {
559
				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
560
			} catch (QueryException $e) {
561
				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
562
			}
563
		} else {
564
			throw new OCSBadRequestException($this->l->t('Unknown share type'));
565
		}
566
567
		$share->setShareType($shareType);
568
		$share->setSharedBy($this->currentUser);
569
570
		try {
571
			$share = $this->shareManager->createShare($share);
572
		} catch (GenericShareException $e) {
573
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
574
			throw new OCSException($e->getHint(), $code);
575
		} catch (\Exception $e) {
576
			throw new OCSForbiddenException($e->getMessage(), $e);
577
		}
578
579
		$output = $this->formatShare($share);
580
581
		return new DataResponse($output);
582
	}
583
584
	/**
585
	 * @param null|Node $node
586
	 * @param boolean $includeTags
587
	 *
588
	 * @return array
589
	 */
590
	private function getSharedWithMe($node, bool $includeTags): array {
591
592
		$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

592
		$userShares = $this->shareManager->getSharedWith($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER, $node, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
593
		$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

593
		$groupShares = $this->shareManager->getSharedWith($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP, $node, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
594
		$circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

594
		$circleShares = $this->shareManager->getSharedWith($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE, $node, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
595
		$roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

595
		$roomShares = $this->shareManager->getSharedWith($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM, $node, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
596
597
		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
598
599
		$shares = array_filter($shares, function(IShare $share) {
600
			return $share->getShareOwner() !== $this->currentUser;
601
		});
602
603
		$formatted = [];
604
		foreach ($shares as $share) {
605
			if ($this->canAccessShare($share)) {
606
				try {
607
					$formatted[] = $this->formatShare($share);
608
				} catch (NotFoundException $e) {
609
					// Ignore this share
610
				}
611
			}
612
		}
613
614
		if ($includeTags) {
615
			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
616
		}
617
618
		return $formatted;
619
	}
620
621
	/**
622
	 * @param \OCP\Files\Node $folder
623
	 *
624
	 * @return array
625
	 * @throws OCSBadRequestException
626
	 * @throws NotFoundException
627
	 */
628
	private function getSharesInDir(Node $folder): array {
629
		if (!($folder instanceof \OCP\Files\Folder)) {
630
			throw new OCSBadRequestException($this->l->t('Not a directory'));
631
		}
632
633
		$nodes = $folder->getDirectoryListing();
634
635
		/** @var \OCP\Share\IShare[] $shares */
636
		$shares = array_reduce($nodes, function($carry, $node) {
637
			$carry = array_merge($carry, $this->getAllShares($node, true));
0 ignored issues
show
Bug introduced by
$this->getAllShares($node, true) of type void is incompatible with the type array|null expected by parameter $array2 of array_merge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

637
			$carry = array_merge($carry, /** @scrutinizer ignore-type */ $this->getAllShares($node, true));
Loading history...
Bug introduced by
Are you sure the usage of $this->getAllShares($node, true) targeting OCA\Files_Sharing\Contro...troller::getAllShares() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
638
			return $carry;
639
		}, []);
640
641
		// filter out duplicate shares
642
		$known = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $known is dead and can be removed.
Loading history...
643
644
645
		$formatted = $miniFormatted = [];
646
		$resharingRight = false;
647
		$known = [];
648
		foreach ($shares as $share) {
649
			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
650
				continue;
651
			}
652
653
			try {
654
				$format = $this->formatShare($share);
655
656
				$known[] = $share->getId();
657
				$formatted[] = $format;
658
				if ($share->getSharedBy() === $this->currentUser) {
659
					$miniFormatted[] = $format;
660
				}
661
				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
662
					$resharingRight = true;
663
				}
664
			} catch (\Exception $e) {
665
				//Ignore this share
666
			}
667
		}
668
669
		if (!$resharingRight) {
670
			$formatted = $miniFormatted;
671
		}
672
673
		return $formatted;
674
	}
675
676
	/**
677
	 * The getShares function.
678
	 *
679
	 * @NoAdminRequired
680
	 *
681
	 * @param string $shared_with_me
682
	 * @param string $reshares
683
	 * @param string $subfiles
684
	 * @param string $path
685
	 *
686
	 * - Get shares by the current user
687
	 * - Get shares by the current user and reshares (?reshares=true)
688
	 * - Get shares with the current user (?shared_with_me=true)
689
	 * - Get shares for a specific path (?path=...)
690
	 * - Get all shares in a folder (?subfiles=true&path=..)
691
	 *
692
	 * @param string $include_tags
693
	 *
694
	 * @return DataResponse
695
	 * @throws NotFoundException
696
	 * @throws OCSBadRequestException
697
	 * @throws OCSNotFoundException
698
	 */
699
	public function getShares(
700
		string $shared_with_me = 'false',
701
		string $reshares = 'false',
702
		string $subfiles = 'false',
703
		string $path = '',
704
		string $include_tags = 'false'
705
	): DataResponse {
706
707
		$node = null;
708
		if ($path !== '') {
709
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
710
			try {
711
				$node = $userFolder->get($path);
712
				$this->lock($node);
713
			} catch (NotFoundException $e) {
714
				throw new OCSNotFoundException(
715
					$this->l->t('Wrong path, file/folder doesn\'t exist')
716
				);
717
			} catch (LockedException $e) {
718
				throw new OCSNotFoundException($this->l->t('Could not lock node'));
719
			}
720
		}
721
722
		$shares = $this->getFormattedShares(
723
			$this->currentUser,
724
			$node,
725
			($shared_with_me === 'true'),
726
			($reshares === 'true'),
727
			($subfiles === 'true'),
728
			($include_tags === 'true')
729
		);
730
731
		return new DataResponse($shares);
732
	}
733
734
735
	/**
736
	 * @param string $viewer
737
	 * @param Node $node
738
	 * @param bool $sharedWithMe
739
	 * @param bool $reShares
740
	 * @param bool $subFiles
741
	 * @param bool $includeTags
742
	 *
743
	 * @return array
744
	 * @throws NotFoundException
745
	 * @throws OCSBadRequestException
746
	 */
747
	private function getFormattedShares(
748
		string $viewer, $node = null, bool $sharedWithMe = false, bool $reShares = false,
749
		bool $subFiles = false, bool $includeTags = false
750
	): array {
751
752
		if ($sharedWithMe) {
753
			return $this->getSharedWithMe($node, $includeTags);
754
		}
755
756
		if ($subFiles) {
757
			return $this->getSharesInDir($node);
758
		}
759
760
		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
761
762
		$known = $formatted = $miniFormatted = [];
763
		$resharingRight = false;
764
		foreach ($shares as $share) {
765
			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
766
				continue;
767
			}
768
769
			$known[] = $share->getId();
770
			try {
771
				/** @var IShare $share */
772
				$format = $this->formatShare($share, $node);
773
				$formatted[] = $format;
774
775
				// let's also build a list of shares created
776
				// by the current user only, in case
777
				// there is no resharing rights
778
				if ($share->getSharedBy() === $this->currentUser) {
779
					$miniFormatted[] = $format;
780
				}
781
782
				// check if one of those share is shared with me
783
				// and if I have resharing rights on it
784
				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
785
					$resharingRight = true;
786
				}
787
			} catch (InvalidPathException | NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
788
			}
789
		}
790
791
		if (!$resharingRight) {
792
			$formatted = $miniFormatted;
793
		}
794
795
		if ($includeTags) {
796
			$formatted =
797
				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
798
		}
799
800
		return $formatted;
801
	}
802
803
804
	/**
805
	 * The getInheritedShares function.
806
	 * returns all shares relative to a file, including parent folders shares rights.
807
	 *
808
	 * @NoAdminRequired
809
	 *
810
	 * @param string $path
811
	 *
812
	 * - Get shares by the current user
813
	 * - Get shares by the current user and reshares (?reshares=true)
814
	 * - Get shares with the current user (?shared_with_me=true)
815
	 * - Get shares for a specific path (?path=...)
816
	 * - Get all shares in a folder (?subfiles=true&path=..)
817
	 *
818
	 * @return DataResponse
819
	 * @throws InvalidPathException
820
	 * @throws NotFoundException
821
	 * @throws OCSNotFoundException
822
	 * @throws OCSBadRequestException
823
	 * @throws SharingRightsException
824
	 */
825
	public function getInheritedShares(string $path): DataResponse {
826
827
		// get Node from (string) path.
828
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
829
		try {
830
			$node = $userFolder->get($path);
831
			$this->lock($node);
832
		} catch (\OCP\Files\NotFoundException $e) {
833
			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
834
		} catch (LockedException $e) {
835
			throw new OCSNotFoundException($this->l->t('Could not lock path'));
836
		}
837
838
		// current User has resharing rights ?
839
		$this->confirmSharingRights($node);
840
841
		// initiate real owner.
842
		$owner = $node->getOwner()
843
					  ->getUID();
844
		if (!$this->userManager->userExists($owner)) {
845
			return new DataResponse([]);
846
		}
847
848
		// get node based on the owner, fix owner in case of external storage
849
		$userFolder = $this->rootFolder->getUserFolder($owner);
850
		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
851
			$owner = $node->getOwner()
852
						  ->getUID();
853
			$userFolder = $this->rootFolder->getUserFolder($owner);
854
			$nodes = $userFolder->getById($node->getId());
855
			$node = array_shift($nodes);
856
		}
857
		$basePath = $userFolder->getPath();
858
859
		// generate node list for each parent folders
860
		/** @var Node[] $nodes */
861
		$nodes = [];
862
		while ($node->getPath() !== $basePath) {
863
			$nodes[] = $node;
864
			$node = $node->getParent();
865
		}
866
867
		// for each nodes, retrieve shares.
868
		$shares = [];
869
		foreach ($nodes as $node) {
870
			$getShares = $this->getFormattedShares($owner, $node, false, true);
871
			$this->mergeFormattedShares($shares, $getShares);
872
		}
873
874
		return new DataResponse(array_values($shares));
875
	}
876
877
878
	/**
879
	 * @NoAdminRequired
880
	 *
881
	 * @param string $id
882
	 * @param int $permissions
883
	 * @param string $password
884
	 * @param string $sendPasswordByTalk
885
	 * @param string $publicUpload
886
	 * @param string $expireDate
887
	 * @param string $note
888
	 * @param string $label
889
	 * @param string $hideDownload
890
	 * @return DataResponse
891
	 * @throws LockedException
892
	 * @throws NotFoundException
893
	 * @throws OCSBadRequestException
894
	 * @throws OCSForbiddenException
895
	 * @throws OCSNotFoundException
896
	 */
897
	public function updateShare(
898
		string $id,
899
		int $permissions = null,
900
		string $password = null,
901
		string $sendPasswordByTalk = null,
902
		string $publicUpload = null,
903
		string $expireDate = null,
904
		string $note = null,
905
		string $label = null,
906
		string $hideDownload = null
907
	): DataResponse {
908
		try {
909
			$share = $this->getShareById($id);
910
		} catch (ShareNotFound $e) {
911
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
912
		}
913
914
		$this->lock($share->getNode());
915
916
		if (!$this->canAccessShare($share, false)) {
917
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
918
		}
919
920
		if (!$this->canEditShare($share)) {
921
			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
922
		}
923
924
		if (
925
			$permissions === null &&
926
			$password === null &&
927
			$sendPasswordByTalk === null &&
928
			$publicUpload === null &&
929
			$expireDate === null &&
930
			$note === null &&
931
			$label === null &&
932
			$hideDownload === null
933
		) {
934
			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
935
		}
936
937
		if ($note !== null) {
938
			$share->setNote($note);
939
		}
940
941
		/**
942
		 * expirationdate, password and publicUpload only make sense for link shares
943
		 */
944
		if ($share->getShareType() === Share::SHARE_TYPE_LINK
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

944
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
945
			|| $share->getShareType() === Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

945
			|| $share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
946
947
			/**
948
			 * We do not allow editing link shares that the current user
949
			 * doesn't own. This is confusing and lead to errors when
950
			 * someone else edit a password or expiration date without
951
			 * the share owner knowing about it.
952
			 * We only allow deletion
953
			 */
954
955
			if ($share->getSharedBy() !== $this->currentUser) {
956
				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
957
			}
958
959
			// Update hide download state
960
			if ($hideDownload === 'true') {
961
				$share->setHideDownload(true);
962
			} else if ($hideDownload === 'false') {
963
				$share->setHideDownload(false);
964
			}
965
966
			$newPermissions = null;
967
			if ($publicUpload === 'true') {
968
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
969
			} else if ($publicUpload === 'false') {
970
				$newPermissions = Constants::PERMISSION_READ;
971
			}
972
973
			if ($permissions !== null) {
974
				$newPermissions = (int) $permissions;
975
				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
976
			}
977
978
			if ($newPermissions !== null &&
979
				!in_array($newPermissions, [
980
					Constants::PERMISSION_READ,
981
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
982
					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
983
					Constants::PERMISSION_CREATE, // hidden file list
984
					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
985
				], true)
986
			) {
987
				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
988
			}
989
990
			if (
991
				// legacy
992
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
993
				// correct
994
				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
995
			) {
996
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
997
					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
998
				}
999
1000
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1001
					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1002
				}
1003
1004
				// normalize to correct public upload permissions
1005
				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1006
			}
1007
1008
			if ($newPermissions !== null) {
1009
				$share->setPermissions($newPermissions);
1010
				$permissions = $newPermissions;
0 ignored issues
show
Unused Code introduced by
The assignment to $permissions is dead and can be removed.
Loading history...
1011
			}
1012
1013
			if ($expireDate === '') {
1014
				$share->setExpirationDate(null);
1015
			} else if ($expireDate !== null) {
1016
				try {
1017
					$expireDate = $this->parseDate($expireDate);
1018
				} catch (\Exception $e) {
1019
					throw new OCSBadRequestException($e->getMessage(), $e);
1020
				}
1021
				$share->setExpirationDate($expireDate);
1022
			}
1023
1024
			if ($password === '') {
1025
				$share->setPassword(null);
1026
			} else if ($password !== null) {
1027
				$share->setPassword($password);
1028
			}
1029
1030
			// only link shares have labels
1031
			if ($share->getShareType() === Share::SHARE_TYPE_LINK && $label !== null) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1031
			if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK && $label !== null) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1032
				$share->setLabel($label);
1033
			}
1034
1035
			if ($sendPasswordByTalk === 'true') {
1036
				if (!$this->appManager->isEnabledForUser('spreed')) {
1037
					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1038
				}
1039
1040
				$share->setSendPasswordByTalk(true);
1041
			} else if ($sendPasswordByTalk !== null) {
1042
				$share->setSendPasswordByTalk(false);
1043
			}
1044
		}
1045
1046
		// NOT A LINK SHARE
1047
		else {
1048
			if ($permissions !== null) {
1049
				$permissions = (int) $permissions;
1050
				$share->setPermissions($permissions);
1051
			}
1052
1053
			if ($expireDate === '') {
1054
				$share->setExpirationDate(null);
1055
			} else if ($expireDate !== null) {
1056
				try {
1057
					$expireDate = $this->parseDate($expireDate);
1058
				} catch (\Exception $e) {
1059
					throw new OCSBadRequestException($e->getMessage(), $e);
1060
				}
1061
				$share->setExpirationDate($expireDate);
1062
			}
1063
		}
1064
1065
		try {
1066
			$share = $this->shareManager->updateShare($share);
1067
		} catch (GenericShareException $e) {
1068
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1069
			throw new OCSException($e->getHint(), $code);
1070
		} catch (\Exception $e) {
1071
			throw new OCSBadRequestException($e->getMessage(), $e);
1072
		}
1073
1074
		return new DataResponse($this->formatShare($share));
1075
	}
1076
1077
	/**
1078
	 * @NoAdminRequired
1079
	 *
1080
	 * @param string $id
1081
	 * @return DataResponse
1082
	 * @throws OCSNotFoundException
1083
	 * @throws OCSException
1084
	 * @throws OCSBadRequestException
1085
	 */
1086
	public function acceptShare(string $id): DataResponse {
1087
		try {
1088
			$share = $this->getShareById($id);
1089
		} catch (ShareNotFound $e) {
1090
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1091
		}
1092
1093
		if (!$this->canAccessShare($share)) {
1094
			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1095
		}
1096
1097
		try {
1098
			$this->shareManager->acceptShare($share, $this->currentUser);
1099
		} catch (GenericShareException $e) {
1100
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1101
			throw new OCSException($e->getHint(), $code);
1102
		} catch (\Exception $e) {
1103
			throw new OCSBadRequestException($e->getMessage(), $e);
1104
		}
1105
1106
		return new DataResponse();
1107
	}
1108
1109
	/**
1110
	 * Does the user have read permission on the share
1111
	 *
1112
	 * @param \OCP\Share\IShare $share the share to check
1113
	 * @param boolean $checkGroups check groups as well?
1114
	 * @return boolean
1115
	 * @throws NotFoundException
1116
	 *
1117
	 * @suppress PhanUndeclaredClassMethod
1118
	 */
1119
	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1120
		// A file with permissions 0 can't be accessed by us. So Don't show it
1121
		if ($share->getPermissions() === 0) {
1122
			return false;
1123
		}
1124
1125
		// Owner of the file and the sharer of the file can always get share
1126
		if ($share->getShareOwner() === $this->currentUser
1127
			|| $share->getSharedBy() === $this->currentUser) {
1128
			return true;
1129
		}
1130
1131
		// If the share is shared with you, you can access it!
1132
		if ($share->getShareType() === Share::SHARE_TYPE_USER
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1132
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1133
			&& $share->getSharedWith() === $this->currentUser) {
1134
			return true;
1135
		}
1136
1137
		// Have reshare rights on the shared file/folder ?
1138
		// Does the currentUser have access to the shared file?
1139
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1140
		$files = $userFolder->getById($share->getNodeId());
1141
		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1142
			return true;
1143
		}
1144
1145
		// If in the recipient group, you can see the share
1146
		if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1146
		if ($checkGroups && $share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1147
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1148
			$user = $this->userManager->get($this->currentUser);
1149
			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1150
				return true;
1151
			}
1152
		}
1153
1154
		if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1154
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1155
			// TODO: have a sanity check like above?
1156
			return true;
1157
		}
1158
1159
		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1159
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1160
			try {
1161
				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1162
			} catch (QueryException $e) {
1163
				return false;
1164
			}
1165
		}
1166
1167
		return false;
1168
	}
1169
1170
	/**
1171
	 * Does the user have edit permission on the share
1172
	 *
1173
	 * @param \OCP\Share\IShare $share the share to check
1174
	 * @return boolean
1175
	 */
1176
	protected function canEditShare(\OCP\Share\IShare $share): bool {
1177
		// A file with permissions 0 can't be accessed by us. So Don't show it
1178
		if ($share->getPermissions() === 0) {
1179
			return false;
1180
		}
1181
1182
		// The owner of the file and the creator of the share
1183
		// can always edit the share
1184
		if ($share->getShareOwner() === $this->currentUser ||
1185
			$share->getSharedBy() === $this->currentUser
1186
		) {
1187
			return true;
1188
		}
1189
1190
		//! we do NOT support some kind of `admin` in groups.
1191
		//! You cannot edit shares shared to a group you're
1192
		//! a member of if you're not the share owner or the file owner!
1193
1194
		return false;
1195
	}
1196
1197
	/**
1198
	 * Does the user have delete permission on the share
1199
	 *
1200
	 * @param \OCP\Share\IShare $share the share to check
1201
	 * @return boolean
1202
	 */
1203
	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1204
		// A file with permissions 0 can't be accessed by us. So Don't show it
1205
		if ($share->getPermissions() === 0) {
1206
			return false;
1207
		}
1208
1209
		// if the user is the recipient, i can unshare
1210
		// the share with self
1211
		if ($share->getShareType() === Share::SHARE_TYPE_USER &&
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1211
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER &&

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1212
			$share->getSharedWith() === $this->currentUser
1213
		) {
1214
			return true;
1215
		}
1216
1217
		// The owner of the file and the creator of the share
1218
		// can always delete the share
1219
		if ($share->getShareOwner() === $this->currentUser ||
1220
			$share->getSharedBy() === $this->currentUser
1221
		) {
1222
			return true;
1223
		}
1224
1225
		return false;
1226
	}
1227
1228
	/**
1229
	 * Does the user have delete permission on the share
1230
	 * This differs from the canDeleteShare function as it only
1231
	 * remove the share for the current user. It does NOT
1232
	 * completely delete the share but only the mount point.
1233
	 * It can then be restored from the deleted shares section.
1234
	 *
1235
	 * @param \OCP\Share\IShare $share the share to check
1236
	 * @return boolean
1237
	 *
1238
	 * @suppress PhanUndeclaredClassMethod
1239
	 */
1240
	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1241
		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1242
			$share->getShareType() !== IShare::TYPE_ROOM
1243
		) {
1244
			return false;
1245
		}
1246
1247
		if ($share->getShareOwner() === $this->currentUser ||
1248
			$share->getSharedBy() === $this->currentUser
1249
		) {
1250
			// Delete the whole share, not just for self
1251
			return false;
1252
		}
1253
1254
		// If in the recipient group, you can delete the share from self
1255
		if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1255
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1256
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1257
			$user = $this->userManager->get($this->currentUser);
1258
			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1259
				return true;
1260
			}
1261
		}
1262
1263
		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1263
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1264
			try {
1265
				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1266
			} catch (QueryException $e) {
1267
				return false;
1268
			}
1269
		}
1270
1271
		return false;
1272
	}
1273
1274
	/**
1275
	 * Make sure that the passed date is valid ISO 8601
1276
	 * So YYYY-MM-DD
1277
	 * If not throw an exception
1278
	 *
1279
	 * @param string $expireDate
1280
	 *
1281
	 * @throws \Exception
1282
	 * @return \DateTime
1283
	 */
1284
	private function parseDate(string $expireDate): \DateTime {
1285
		try {
1286
			$date = new \DateTime($expireDate);
1287
		} catch (\Exception $e) {
1288
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1289
		}
1290
1291
		if ($date === false) {
0 ignored issues
show
introduced by
The condition $date === false is always false.
Loading history...
1292
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1293
		}
1294
1295
		$date->setTime(0, 0, 0);
1296
1297
		return $date;
1298
	}
1299
1300
	/**
1301
	 * Since we have multiple providers but the OCS Share API v1 does
1302
	 * not support this we need to check all backends.
1303
	 *
1304
	 * @param string $id
1305
	 * @return \OCP\Share\IShare
1306
	 * @throws ShareNotFound
1307
	 */
1308
	private function getShareById(string $id): IShare {
1309
		$share = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $share is dead and can be removed.
Loading history...
1310
1311
		// First check if it is an internal share.
1312
		try {
1313
			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1314
			return $share;
1315
		} catch (ShareNotFound $e) {
1316
			// Do nothing, just try the other share type
1317
		}
1318
1319
1320
		try {
1321
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1321
			if ($this->shareManager->shareProviderExists(/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE)) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1322
				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1323
				return $share;
1324
			}
1325
		} catch (ShareNotFound $e) {
1326
			// Do nothing, just try the other share type
1327
		}
1328
1329
		try {
1330
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1330
			if ($this->shareManager->shareProviderExists(/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL)) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1331
				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1332
				return $share;
1333
			}
1334
		} catch (ShareNotFound $e) {
1335
			// Do nothing, just try the other share type
1336
		}
1337
1338
		try {
1339
			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1340
			return $share;
1341
		} catch (ShareNotFound $e) {
1342
			// Do nothing, just try the other share type
1343
		}
1344
1345
		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1346
			throw new ShareNotFound();
1347
		}
1348
		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1349
1350
		return $share;
1351
	}
1352
1353
	/**
1354
	 * Lock a Node
1355
	 *
1356
	 * @param \OCP\Files\Node $node
1357
	 * @throws LockedException
1358
	 */
1359
	private function lock(\OCP\Files\Node $node) {
1360
		$node->lock(ILockingProvider::LOCK_SHARED);
1361
		$this->lockedNode = $node;
1362
	}
1363
1364
	/**
1365
	 * Cleanup the remaining locks
1366
	 * @throws @LockedException
1367
	 */
1368
	public function cleanup() {
1369
		if ($this->lockedNode !== null) {
1370
			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1371
		}
1372
	}
1373
1374
	/**
1375
	 * Returns the helper of ShareAPIController for room shares.
1376
	 *
1377
	 * If the Talk application is not enabled or the helper is not available
1378
	 * a QueryException is thrown instead.
1379
	 *
1380
	 * @return \OCA\Talk\Share\Helper\ShareAPIController
0 ignored issues
show
Bug introduced by
The type OCA\Talk\Share\Helper\ShareAPIController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1381
	 * @throws QueryException
1382
	 */
1383
	private function getRoomShareHelper() {
1384
		if (!$this->appManager->isEnabledForUser('spreed')) {
1385
			throw new QueryException();
1386
		}
1387
1388
		return $this->serverContainer->query('\OCA\Talk\Share\Helper\ShareAPIController');
1389
	}
1390
1391
1392
	/**
1393
	 * @param string $viewer
1394
	 * @param Node $node
1395
	 * @param bool $reShares
1396
	 *
1397
	 * @return IShare[]
1398
	 */
1399
	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1400
1401
		$providers = [
1402
			Share::SHARE_TYPE_USER,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1402
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1403
			Share::SHARE_TYPE_GROUP,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1403
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1404
			Share::SHARE_TYPE_LINK,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1404
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1405
			Share::SHARE_TYPE_EMAIL,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1405
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1406
			Share::SHARE_TYPE_EMAIL,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1406
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1407
			Share::SHARE_TYPE_CIRCLE,
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1407
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1408
			Share::SHARE_TYPE_ROOM
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1408
			/** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1409
		];
1410
1411
		// Should we assume that the (currentUser) viewer is the owner of the node !?
1412
		$shares = [];
1413
		foreach ($providers as $provider) {
1414
			if (!$this->shareManager->shareProviderExists($provider)) {
1415
				continue;
1416
			}
1417
1418
			$providerShares =
1419
				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1420
			$shares = array_merge($shares, $providerShares);
1421
		}
1422
1423
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1424
			$federatedShares = $this->shareManager->getSharesBy(
1425
				$this->currentUser, Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE has been deprecated: 17.0.0 - use IShare::TYPE_REMOTE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1425
				$this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1426
			);
1427
			$shares = array_merge($shares, $federatedShares);
1428
		}
1429
1430
		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1431
			$federatedShares = $this->shareManager->getSharesBy(
1432
				$this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE_GROUP has been deprecated: 17.0.0 - use IShare::REMOTE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1432
				$this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1433
			);
1434
			$shares = array_merge($shares, $federatedShares);
1435
		}
1436
1437
		return $shares;
1438
	}
1439
1440
1441
	/**
1442
	 * @param Node $node
1443
	 *
1444
	 * @throws SharingRightsException
1445
	 */
1446
	private function confirmSharingRights(Node $node): void {
1447
		if (!$this->hasResharingRights($this->currentUser, $node)) {
1448
			throw new SharingRightsException('no sharing rights on this item');
1449
		}
1450
	}
1451
1452
1453
	/**
1454
	 * @param string $viewer
1455
	 * @param Node $node
1456
	 *
1457
	 * @return bool
1458
	 */
1459
	private function hasResharingRights($viewer, $node): bool {
1460
		foreach ([$node, $node->getParent()] as $node) {
0 ignored issues
show
introduced by
$node is overwriting one of the parameters of this function.
Loading history...
1461
			$shares = $this->getSharesFromNode($viewer, $node, true);
1462
			foreach ($shares as $share) {
1463
				try {
1464
					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1465
						return true;
1466
					}
1467
				} catch (InvalidPathException | NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1468
				}
1469
			}
1470
		}
1471
1472
		return false;
1473
	}
1474
1475
1476
	/**
1477
	 * Returns if we can find resharing rights in an IShare object for a specific user.
1478
	 *
1479
	 * @suppress PhanUndeclaredClassMethod
1480
	 *
1481
	 * @param string $userId
1482
	 * @param IShare $share
1483
	 * @param Node $node
1484
	 *
1485
	 * @return bool
1486
	 * @throws NotFoundException
1487
	 * @throws InvalidPathException
1488
	 */
1489
	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1490
		if ($share->getShareOwner() === $userId) {
1491
			return true;
1492
		}
1493
1494
		// we check that current user have parent resharing rights on the current file
1495
		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1496
			return true;
1497
		}
1498
1499
		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1500
			return false;
1501
		}
1502
1503
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1503
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1504
			return true;
1505
		}
1506
1507
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1507
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1508
			return true;
1509
		}
1510
1511
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1511
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1512
			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1513
1514
			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1515
			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1516
			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1517
			if (is_bool($shareWithLength)) {
0 ignored issues
show
introduced by
The condition is_bool($shareWithLength) is always false.
Loading history...
1518
				$shareWithLength = -1;
1519
			}
1520
			$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1521
			try {
1522
				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1523
				if ($member->getLevel() >= 4) {
1524
					return true;
1525
				}
1526
				return false;
1527
			} catch (QueryException $e) {
1528
				return false;
1529
			}
1530
		}
1531
1532
		return false;
1533
	}
1534
1535
	/**
1536
	 * Get all the shares for the current user
1537
	 *
1538
	 * @param Node|null $path
1539
	 * @param boolean $reshares
1540
	 * @return void
1541
	 */
1542
	private function getAllShares(?Node $path = null, bool $reshares = false) {
1543
		// Get all shares
1544
		$userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1544
		$userShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1545
		$groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1545
		$groupShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1546
		$linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1546
		$linkShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1547
1548
		// EMAIL SHARES
1549
		$mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1549
		$mailShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1550
1551
		// CIRCLE SHARES
1552
		$circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1552
		$circleShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1553
1554
		// TALK SHARES
1555
		$roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1555
		$roomShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1556
1557
		// FEDERATION
1558
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1559
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE has been deprecated: 17.0.0 - use IShare::TYPE_REMOTE instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1559
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1560
		} else {
1561
			$federatedShares = [];
1562
		}
1563
		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1564
			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE_GROUP has been deprecated: 17.0.0 - use IShare::REMOTE_GROUP instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1564
			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1565
		} else {
1566
			$federatedGroupShares = [];
1567
		}
1568
1569
		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $federatedShares, $federatedGroupShares);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_merge($user... $federatedGroupShares) returns the type array which is incompatible with the documented return type void.
Loading history...
1570
	}
1571
1572
1573
	/**
1574
	 * merging already formatted shares.
1575
	 * We'll make an associative array to easily detect duplicate Ids.
1576
	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1577
	 *
1578
	 * @param array $shares
1579
	 * @param array $newShares
1580
	 */
1581
	private function mergeFormattedShares(array &$shares, array $newShares) {
1582
		foreach ($newShares as $newShare) {
1583
			if (!array_key_exists($newShare['id'], $shares)) {
1584
				$shares[$newShare['id']] = $newShare;
1585
			}
1586
		}
1587
	}
1588
1589
}
1590