Passed
Push — master ( 7d5b0c...557c49 )
by Roeland
13:29 queued 12s
created

Manager::createShare()   D

Complexity

Conditions 18
Paths 144

Size

Total Lines 134
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 76
c 1
b 0
f 0
nc 144
nop 1
dl 0
loc 134
rs 4.5

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
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Daniel Calviño Sánchez <[email protected]>
10
 * @author Jan-Christoph Borchardt <[email protected]>
11
 * @author Joas Schilling <[email protected]>
12
 * @author John Molakvoæ (skjnldsv) <[email protected]>
13
 * @author Julius Härtl <[email protected]>
14
 * @author Lukas Reschke <[email protected]>
15
 * @author Maxence Lange <[email protected]>
16
 * @author Maxence Lange <[email protected]>
17
 * @author Morris Jobke <[email protected]>
18
 * @author Pauli Järvinen <[email protected]>
19
 * @author Robin Appelman <[email protected]>
20
 * @author Roeland Jago Douma <[email protected]>
21
 * @author Stephan Müller <[email protected]>
22
 * @author Thibault Coupin <[email protected]>
23
 * @author Vincent Petry <[email protected]>
24
 *
25
 * @license AGPL-3.0
26
 *
27
 * This code is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License, version 3,
29
 * as published by the Free Software Foundation.
30
 *
31
 * This program is distributed in the hope that it will be useful,
32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
 * GNU Affero General Public License for more details.
35
 *
36
 * You should have received a copy of the GNU Affero General Public License, version 3,
37
 * along with this program. If not, see <http://www.gnu.org/licenses/>
38
 *
39
 */
40
41
namespace OC\Share20;
42
43
use OC\Cache\CappedMemoryCache;
44
use OC\Files\Mount\MoveableMount;
45
use OC\HintException;
46
use OC\Share20\Exception\ProviderException;
47
use OCP\EventDispatcher\IEventDispatcher;
48
use OCP\Files\File;
49
use OCP\Files\Folder;
50
use OCP\Files\IRootFolder;
51
use OCP\Files\Mount\IMountManager;
52
use OCP\Files\Node;
53
use OCP\IConfig;
54
use OCP\IGroupManager;
55
use OCP\IL10N;
56
use OCP\ILogger;
57
use OCP\IURLGenerator;
58
use OCP\IUser;
59
use OCP\IUserManager;
60
use OCP\L10N\IFactory;
61
use OCP\Mail\IMailer;
62
use OCP\Security\Events\ValidatePasswordPolicyEvent;
63
use OCP\Security\IHasher;
64
use OCP\Security\ISecureRandom;
65
use OCP\Share;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, OC\Share20\Share. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
66
use OCP\Share\Exceptions\GenericShareException;
67
use OCP\Share\Exceptions\ShareNotFound;
68
use OCP\Share\IManager;
69
use OCP\Share\IProviderFactory;
70
use OCP\Share\IShare;
71
use OCP\Share\IShareProvider;
72
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
73
use Symfony\Component\EventDispatcher\GenericEvent;
74
75
/**
76
 * This class is the communication hub for all sharing related operations.
77
 */
78
class Manager implements IManager {
79
80
	/** @var IProviderFactory */
81
	private $factory;
82
	/** @var ILogger */
83
	private $logger;
84
	/** @var IConfig */
85
	private $config;
86
	/** @var ISecureRandom */
87
	private $secureRandom;
88
	/** @var IHasher */
89
	private $hasher;
90
	/** @var IMountManager */
91
	private $mountManager;
92
	/** @var IGroupManager */
93
	private $groupManager;
94
	/** @var IL10N */
95
	private $l;
96
	/** @var IFactory */
97
	private $l10nFactory;
98
	/** @var IUserManager */
99
	private $userManager;
100
	/** @var IRootFolder */
101
	private $rootFolder;
102
	/** @var CappedMemoryCache */
103
	private $sharingDisabledForUsersCache;
104
	/** @var EventDispatcherInterface */
105
	private $legacyDispatcher;
106
	/** @var LegacyHooks */
107
	private $legacyHooks;
108
	/** @var IMailer */
109
	private $mailer;
110
	/** @var IURLGenerator */
111
	private $urlGenerator;
112
	/** @var \OC_Defaults */
113
	private $defaults;
114
	/** @var IEventDispatcher */
115
	private $dispatcher;
116
117
118
	/**
119
	 * Manager constructor.
120
	 *
121
	 * @param ILogger $logger
122
	 * @param IConfig $config
123
	 * @param ISecureRandom $secureRandom
124
	 * @param IHasher $hasher
125
	 * @param IMountManager $mountManager
126
	 * @param IGroupManager $groupManager
127
	 * @param IL10N $l
128
	 * @param IFactory $l10nFactory
129
	 * @param IProviderFactory $factory
130
	 * @param IUserManager $userManager
131
	 * @param IRootFolder $rootFolder
132
	 * @param EventDispatcherInterface $eventDispatcher
133
	 * @param IMailer $mailer
134
	 * @param IURLGenerator $urlGenerator
135
	 * @param \OC_Defaults $defaults
136
	 */
137
	public function __construct(
138
			ILogger $logger,
139
			IConfig $config,
140
			ISecureRandom $secureRandom,
141
			IHasher $hasher,
142
			IMountManager $mountManager,
143
			IGroupManager $groupManager,
144
			IL10N $l,
145
			IFactory $l10nFactory,
146
			IProviderFactory $factory,
147
			IUserManager $userManager,
148
			IRootFolder $rootFolder,
149
			EventDispatcherInterface $legacyDispatcher,
150
			IMailer $mailer,
151
			IURLGenerator $urlGenerator,
152
			\OC_Defaults $defaults,
153
			IEventDispatcher $dispatcher
154
	) {
155
		$this->logger = $logger;
156
		$this->config = $config;
157
		$this->secureRandom = $secureRandom;
158
		$this->hasher = $hasher;
159
		$this->mountManager = $mountManager;
160
		$this->groupManager = $groupManager;
161
		$this->l = $l;
162
		$this->l10nFactory = $l10nFactory;
163
		$this->factory = $factory;
164
		$this->userManager = $userManager;
165
		$this->rootFolder = $rootFolder;
166
		$this->legacyDispatcher = $legacyDispatcher;
167
		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
168
		$this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
169
		$this->mailer = $mailer;
170
		$this->urlGenerator = $urlGenerator;
171
		$this->defaults = $defaults;
172
		$this->dispatcher = $dispatcher;
173
	}
174
175
	/**
176
	 * Convert from a full share id to a tuple (providerId, shareId)
177
	 *
178
	 * @param string $id
179
	 * @return string[]
180
	 */
181
	private function splitFullId($id) {
182
		return explode(':', $id, 2);
183
	}
184
185
	/**
186
	 * Verify if a password meets all requirements
187
	 *
188
	 * @param string $password
189
	 * @throws \Exception
190
	 */
191
	protected function verifyPassword($password) {
192
		if ($password === null) {
0 ignored issues
show
introduced by
The condition $password === null is always false.
Loading history...
193
			// No password is set, check if this is allowed.
194
			if ($this->shareApiLinkEnforcePassword()) {
195
				throw new \InvalidArgumentException('Passwords are enforced for link shares');
196
			}
197
198
			return;
199
		}
200
201
		// Let others verify the password
202
		try {
203
			$this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
204
		} catch (HintException $e) {
205
			throw new \Exception($e->getHint());
206
		}
207
	}
208
209
	/**
210
	 * Check for generic requirements before creating a share
211
	 *
212
	 * @param \OCP\Share\IShare $share
213
	 * @throws \InvalidArgumentException
214
	 * @throws GenericShareException
215
	 *
216
	 * @suppress PhanUndeclaredClassMethod
217
	 */
218
	protected function generalCreateChecks(\OCP\Share\IShare $share) {
219
		if ($share->getShareType() === \OCP\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

219
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
220
			// We expect a valid user as sharedWith for user shares
221
			if (!$this->userManager->userExists($share->getSharedWith())) {
222
				throw new \InvalidArgumentException('SharedWith is not a valid user');
223
			}
224
		} else if ($share->getShareType() === \OCP\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

224
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
225
			// We expect a valid group as sharedWith for group shares
226
			if (!$this->groupManager->groupExists($share->getSharedWith())) {
227
				throw new \InvalidArgumentException('SharedWith is not a valid group');
228
			}
229
		} else if ($share->getShareType() === \OCP\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

229
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
230
			if ($share->getSharedWith() !== null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() !== null is always true.
Loading history...
231
				throw new \InvalidArgumentException('SharedWith should be empty');
232
			}
233
		} else if ($share->getShareType() === \OCP\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

233
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
234
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
235
				throw new \InvalidArgumentException('SharedWith should not be empty');
236
			}
237
		}  else if ($share->getShareType() === \OCP\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

237
		}  else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
238
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
239
				throw new \InvalidArgumentException('SharedWith should not be empty');
240
			}
241
		} else if ($share->getShareType() === \OCP\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

241
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
242
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
243
				throw new \InvalidArgumentException('SharedWith should not be empty');
244
			}
245
		} else if ($share->getShareType() === \OCP\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

245
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
246
			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
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...
247
			if ($circle === null) {
248
				throw new \InvalidArgumentException('SharedWith is not a valid circle');
249
			}
250
		} else if ($share->getShareType() === \OCP\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

250
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
251
		} else {
252
			// We can't handle other types yet
253
			throw new \InvalidArgumentException('unknown share type');
254
		}
255
256
		// Verify the initiator of the share is set
257
		if ($share->getSharedBy() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedBy() === null is always false.
Loading history...
258
			throw new \InvalidArgumentException('SharedBy should be set');
259
		}
260
261
		// Cannot share with yourself
262
		if ($share->getShareType() === \OCP\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

262
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
263
			$share->getSharedWith() === $share->getSharedBy()) {
264
			throw new \InvalidArgumentException('Can’t share with yourself');
265
		}
266
267
		// The path should be set
268
		if ($share->getNode() === null) {
269
			throw new \InvalidArgumentException('Path should be set');
270
		}
271
272
		// And it should be a file or a folder
273
		if (!($share->getNode() instanceof \OCP\Files\File) &&
274
				!($share->getNode() instanceof \OCP\Files\Folder)) {
0 ignored issues
show
introduced by
$share->getNode() is always a sub-type of OCP\Files\Folder.
Loading history...
275
			throw new \InvalidArgumentException('Path should be either a file or a folder');
276
		}
277
278
		// And you can't share your rootfolder
279
		if ($this->userManager->userExists($share->getSharedBy())) {
280
			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
281
			$userFolderPath = $userFolder->getPath();
282
		} else {
283
			$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
284
			$userFolderPath = $userFolder->getPath();
285
		}
286
		if ($userFolderPath === $share->getNode()->getPath()) {
287
			throw new \InvalidArgumentException('You can’t share your root folder');
288
		}
289
290
		// Check if we actually have share permissions
291
		if (!$share->getNode()->isShareable()) {
292
			$path = $userFolder->getRelativePath($share->getNode()->getPath());
293
			$message_t = $this->l->t('You are not allowed to share %s', [$path]);
294
			throw new GenericShareException($message_t, $message_t, 404);
295
		}
296
297
		// Permissions should be set
298
		if ($share->getPermissions() === null) {
0 ignored issues
show
introduced by
The condition $share->getPermissions() === null is always false.
Loading history...
299
			throw new \InvalidArgumentException('A share requires permissions');
300
		}
301
302
		$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
303
		$permissions = 0;
304
		$mount = $share->getNode()->getMountPoint();
305
		if (!$isFederatedShare && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
			// When it's a reshare use the parent share permissions as maximum
307
			$userMountPointId = $mount->getStorageRootId();
308
			$userMountPoints = $userFolder->getById($userMountPointId);
309
			$userMountPoint = array_shift($userMountPoints);
310
311
			/* Check if this is an incoming share */
312
			$incomingShares = $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_USER, $userMountPoint, -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

312
			$incomingShares = $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER, $userMountPoint, -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...
313
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_GROUP, $userMountPoint, -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

313
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP, $userMountPoint, -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...
314
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_CIRCLE, $userMountPoint, -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

314
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE, $userMountPoint, -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...
315
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_ROOM, $userMountPoint, -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

315
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM, $userMountPoint, -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...
316
317
			/** @var \OCP\Share\IShare[] $incomingShares */
318
			if (!empty($incomingShares)) {
319
				foreach ($incomingShares as $incomingShare) {
320
					$permissions |= $incomingShare->getPermissions();
321
				}
322
			}
323
		} else {
324
			/*
325
			 * Quick fix for #23536
326
			 * Non moveable mount points do not have update and delete permissions
327
			 * while we 'most likely' do have that on the storage.
328
			 */
329
			$permissions = $share->getNode()->getPermissions();
330
			if (!($mount instanceof MoveableMount)) {
331
				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
332
			}
333
		}
334
335
		// Check that we do not share with more permissions than we have
336
		if ($share->getPermissions() & ~$permissions) {
337
			$path = $userFolder->getRelativePath($share->getNode()->getPath());
338
			$message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
339
			throw new GenericShareException($message_t, $message_t, 404);
340
		}
341
342
343
		// Check that read permissions are always set
344
		// Link shares are allowed to have no read permissions to allow upload to hidden folders
345
		$noReadPermissionRequired = $share->getShareType() === \OCP\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

345
		$noReadPermissionRequired = $share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
346
			|| $share->getShareType() === \OCP\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

346
			|| $share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
347
		if (!$noReadPermissionRequired &&
348
			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
349
			throw new \InvalidArgumentException('Shares need at least read permissions');
350
		}
351
352
		if ($share->getNode() instanceof \OCP\Files\File) {
353
			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
354
				$message_t = $this->l->t('Files can’t be shared with delete permissions');
355
				throw new GenericShareException($message_t);
356
			}
357
			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
358
				$message_t = $this->l->t('Files can’t be shared with create permissions');
359
				throw new GenericShareException($message_t);
360
			}
361
		}
362
	}
363
364
	/**
365
	 * Validate if the expiration date fits the system settings
366
	 *
367
	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
368
	 * @return \OCP\Share\IShare The modified share object
369
	 * @throws GenericShareException
370
	 * @throws \InvalidArgumentException
371
	 * @throws \Exception
372
	 */
373
	protected function validateExpirationDateInternal(\OCP\Share\IShare $share) {
374
		$expirationDate = $share->getExpirationDate();
375
376
		if ($expirationDate !== null) {
377
			//Make sure the expiration date is a date
378
			$expirationDate->setTime(0, 0, 0);
379
380
			$date = new \DateTime();
381
			$date->setTime(0, 0, 0);
382
			if ($date >= $expirationDate) {
383
				$message = $this->l->t('Expiration date is in the past');
384
				throw new GenericShareException($message, $message, 404);
385
			}
386
		}
387
388
		// If expiredate is empty set a default one if there is a default
389
		$fullId = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $fullId is dead and can be removed.
Loading history...
390
		try {
391
			$fullId = $share->getFullId();
392
		} catch (\UnexpectedValueException $e) {
393
			// This is a new share
394
		}
395
396
		if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
0 ignored issues
show
introduced by
The condition $fullId === null is always false.
Loading history...
397
			$expirationDate = new \DateTime();
398
			$expirationDate->setTime(0,0,0);
399
			$expirationDate->add(new \DateInterval('P'.$this->shareApiInternalDefaultExpireDays().'D'));
400
		}
401
402
		// If we enforce the expiration date check that is does not exceed
403
		if ($this->shareApiInternalDefaultExpireDateEnforced()) {
404
			if ($expirationDate === null) {
405
				throw new \InvalidArgumentException('Expiration date is enforced');
406
			}
407
408
			$date = new \DateTime();
409
			$date->setTime(0, 0, 0);
410
			$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
411
			if ($date < $expirationDate) {
412
				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
413
				throw new GenericShareException($message, $message, 404);
414
			}
415
		}
416
417
		$accepted = true;
418
		$message = '';
419
		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
420
			'expirationDate' => &$expirationDate,
421
			'accepted' => &$accepted,
422
			'message' => &$message,
423
			'passwordSet' => $share->getPassword() !== null,
424
		]);
425
426
		if (!$accepted) {
0 ignored issues
show
introduced by
The condition $accepted is always true.
Loading history...
427
			throw new \Exception($message);
428
		}
429
430
		$share->setExpirationDate($expirationDate);
431
432
		return $share;
433
	}
434
435
	/**
436
	 * Validate if the expiration date fits the system settings
437
	 *
438
	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
439
	 * @return \OCP\Share\IShare The modified share object
440
	 * @throws GenericShareException
441
	 * @throws \InvalidArgumentException
442
	 * @throws \Exception
443
	 */
444
	protected function validateExpirationDate(\OCP\Share\IShare $share) {
445
446
		$expirationDate = $share->getExpirationDate();
447
448
		if ($expirationDate !== null) {
449
			//Make sure the expiration date is a date
450
			$expirationDate->setTime(0, 0, 0);
451
452
			$date = new \DateTime();
453
			$date->setTime(0, 0, 0);
454
			if ($date >= $expirationDate) {
455
				$message = $this->l->t('Expiration date is in the past');
456
				throw new GenericShareException($message, $message, 404);
457
			}
458
		}
459
460
		// If expiredate is empty set a default one if there is a default
461
		$fullId = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $fullId is dead and can be removed.
Loading history...
462
		try {
463
			$fullId = $share->getFullId();
464
		} catch (\UnexpectedValueException $e) {
465
			// This is a new share
466
		}
467
468
		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
0 ignored issues
show
introduced by
The condition $fullId === null is always false.
Loading history...
469
			$expirationDate = new \DateTime();
470
			$expirationDate->setTime(0,0,0);
471
			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
472
		}
473
474
		// If we enforce the expiration date check that is does not exceed
475
		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
476
			if ($expirationDate === null) {
477
				throw new \InvalidArgumentException('Expiration date is enforced');
478
			}
479
480
			$date = new \DateTime();
481
			$date->setTime(0, 0, 0);
482
			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
483
			if ($date < $expirationDate) {
484
				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
485
				throw new GenericShareException($message, $message, 404);
486
			}
487
		}
488
489
		$accepted = true;
490
		$message = '';
491
		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
492
			'expirationDate' => &$expirationDate,
493
			'accepted' => &$accepted,
494
			'message' => &$message,
495
			'passwordSet' => $share->getPassword() !== null,
496
		]);
497
498
		if (!$accepted) {
0 ignored issues
show
introduced by
The condition $accepted is always true.
Loading history...
499
			throw new \Exception($message);
500
		}
501
502
		$share->setExpirationDate($expirationDate);
503
504
		return $share;
505
	}
506
507
	/**
508
	 * Check for pre share requirements for user shares
509
	 *
510
	 * @param \OCP\Share\IShare $share
511
	 * @throws \Exception
512
	 */
513
	protected function userCreateChecks(\OCP\Share\IShare $share) {
514
		// Check if we can share with group members only
515
		if ($this->shareWithGroupMembersOnly()) {
516
			$sharedBy = $this->userManager->get($share->getSharedBy());
517
			$sharedWith = $this->userManager->get($share->getSharedWith());
518
			// Verify we can share with this user
519
			$groups = array_intersect(
520
					$this->groupManager->getUserGroupIds($sharedBy),
521
					$this->groupManager->getUserGroupIds($sharedWith)
522
			);
523
			if (empty($groups)) {
524
				throw new \Exception('Sharing is only allowed with group members');
525
			}
526
		}
527
528
		/*
529
		 * TODO: Could be costly, fix
530
		 *
531
		 * Also this is not what we want in the future.. then we want to squash identical shares.
532
		 */
533
		$provider = $this->factory->getProviderForType(\OCP\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

533
		$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
534
		$existingShares = $provider->getSharesByPath($share->getNode());
535
		foreach($existingShares as $existingShare) {
536
			// Ignore if it is the same share
537
			try {
538
				if ($existingShare->getFullId() === $share->getFullId()) {
539
					continue;
540
				}
541
			} catch (\UnexpectedValueException $e) {
542
				//Shares are not identical
543
			}
544
545
			// Identical share already existst
546
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
547
				throw new \Exception('Path is already shared with this user');
548
			}
549
550
			// The share is already shared with this user via a group share
551
			if ($existingShare->getShareType() === \OCP\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

551
			if ($existingShare->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
552
				$group = $this->groupManager->get($existingShare->getSharedWith());
553
				if (!is_null($group)) {
554
					$user = $this->userManager->get($share->getSharedWith());
555
556
					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
557
						throw new \Exception('Path is already shared with this user');
558
					}
559
				}
560
			}
561
		}
562
	}
563
564
	/**
565
	 * Check for pre share requirements for group shares
566
	 *
567
	 * @param \OCP\Share\IShare $share
568
	 * @throws \Exception
569
	 */
570
	protected function groupCreateChecks(\OCP\Share\IShare $share) {
571
		// Verify group shares are allowed
572
		if (!$this->allowGroupSharing()) {
573
			throw new \Exception('Group sharing is now allowed');
574
		}
575
576
		// Verify if the user can share with this group
577
		if ($this->shareWithGroupMembersOnly()) {
578
			$sharedBy = $this->userManager->get($share->getSharedBy());
579
			$sharedWith = $this->groupManager->get($share->getSharedWith());
580
			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
581
				throw new \Exception('Sharing is only allowed within your own groups');
582
			}
583
		}
584
585
		/*
586
		 * TODO: Could be costly, fix
587
		 *
588
		 * Also this is not what we want in the future.. then we want to squash identical shares.
589
		 */
590
		$provider = $this->factory->getProviderForType(\OCP\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

590
		$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
591
		$existingShares = $provider->getSharesByPath($share->getNode());
592
		foreach($existingShares as $existingShare) {
593
			try {
594
				if ($existingShare->getFullId() === $share->getFullId()) {
595
					continue;
596
				}
597
			} catch (\UnexpectedValueException $e) {
598
				//It is a new share so just continue
599
			}
600
601
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
602
				throw new \Exception('Path is already shared with this group');
603
			}
604
		}
605
	}
606
607
	/**
608
	 * Check for pre share requirements for link shares
609
	 *
610
	 * @param \OCP\Share\IShare $share
611
	 * @throws \Exception
612
	 */
613
	protected function linkCreateChecks(\OCP\Share\IShare $share) {
614
		// Are link shares allowed?
615
		if (!$this->shareApiAllowLinks()) {
616
			throw new \Exception('Link sharing is not allowed');
617
		}
618
619
		// Link shares by definition can't have share permissions
620
		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
621
			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
622
		}
623
624
		// Check if public upload is allowed
625
		if (!$this->shareApiLinkAllowPublicUpload() &&
626
			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
627
			throw new \InvalidArgumentException('Public upload is not allowed');
628
		}
629
	}
630
631
	/**
632
	 * To make sure we don't get invisible link shares we set the parent
633
	 * of a link if it is a reshare. This is a quick word around
634
	 * until we can properly display multiple link shares in the UI
635
	 *
636
	 * See: https://github.com/owncloud/core/issues/22295
637
	 *
638
	 * FIXME: Remove once multiple link shares can be properly displayed
639
	 *
640
	 * @param \OCP\Share\IShare $share
641
	 */
642
	protected function setLinkParent(\OCP\Share\IShare $share) {
643
644
		// No sense in checking if the method is not there.
645
		if (method_exists($share, 'setParent')) {
646
			$storage = $share->getNode()->getStorage();
647
			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
648
				/** @var \OCA\Files_Sharing\SharedStorage $storage */
649
				$share->setParent($storage->getShareId());
650
			}
651
		}
652
	}
653
654
	/**
655
	 * @param File|Folder $path
656
	 */
657
	protected function pathCreateChecks($path) {
658
		// Make sure that we do not share a path that contains a shared mountpoint
659
		if ($path instanceof \OCP\Files\Folder) {
660
			$mounts = $this->mountManager->findIn($path->getPath());
661
			foreach($mounts as $mount) {
662
				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
663
					throw new \InvalidArgumentException('Path contains files shared with you');
664
				}
665
			}
666
		}
667
	}
668
669
	/**
670
	 * Check if the user that is sharing can actually share
671
	 *
672
	 * @param \OCP\Share\IShare $share
673
	 * @throws \Exception
674
	 */
675
	protected function canShare(\OCP\Share\IShare $share) {
676
		if (!$this->shareApiEnabled()) {
677
			throw new \Exception('Sharing is disabled');
678
		}
679
680
		if ($this->sharingDisabledForUser($share->getSharedBy())) {
681
			throw new \Exception('Sharing is disabled for you');
682
		}
683
	}
684
685
	/**
686
	 * Share a path
687
	 *
688
	 * @param \OCP\Share\IShare $share
689
	 * @return Share The share object
690
	 * @throws \Exception
691
	 *
692
	 * TODO: handle link share permissions or check them
693
	 */
694
	public function createShare(\OCP\Share\IShare $share) {
695
		$this->canShare($share);
696
697
		$this->generalCreateChecks($share);
698
699
		// Verify if there are any issues with the path
700
		$this->pathCreateChecks($share->getNode());
701
702
		/*
703
		 * On creation of a share the owner is always the owner of the path
704
		 * Except for mounted federated shares.
705
		 */
706
		$storage = $share->getNode()->getStorage();
707
		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
708
			$parent = $share->getNode()->getParent();
709
			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
710
				$parent = $parent->getParent();
711
			}
712
			$share->setShareOwner($parent->getOwner()->getUID());
713
		} else {
714
			$share->setShareOwner($share->getNode()->getOwner()->getUID());
715
		}
716
717
		//Verify share type
718
		if ($share->getShareType() === \OCP\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

718
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
719
			$this->userCreateChecks($share);
720
721
			//Verify the expiration date
722
			$share = $this->validateExpirationDateInternal($share);
723
724
		} else if ($share->getShareType() === \OCP\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

724
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
725
			$this->groupCreateChecks($share);
726
727
			//Verify the expiration date
728
			$share = $this->validateExpirationDateInternal($share);
729
730
		} else if ($share->getShareType() === \OCP\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

730
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
731
			$this->linkCreateChecks($share);
732
			$this->setLinkParent($share);
733
734
			/*
735
			 * For now ignore a set token.
736
			 */
737
			$share->setToken(
738
				$this->secureRandom->generate(
739
					\OC\Share\Constants::TOKEN_LENGTH,
740
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
741
				)
742
			);
743
744
			//Verify the expiration date
745
			$share = $this->validateExpirationDate($share);
746
747
			//Verify the password
748
			$this->verifyPassword($share->getPassword());
749
750
			// If a password is set. Hash it!
751
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
752
				$share->setPassword($this->hasher->hash($share->getPassword()));
753
			}
754
		} else if ($share->getShareType() === \OCP\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

754
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
755
			$share->setToken(
756
				$this->secureRandom->generate(
757
					\OC\Share\Constants::TOKEN_LENGTH,
758
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
759
				)
760
			);
761
		}
762
763
		// Cannot share with the owner
764
		if ($share->getShareType() === \OCP\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

764
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
765
			$share->getSharedWith() === $share->getShareOwner()) {
766
			throw new \InvalidArgumentException('Can’t share with the share owner');
767
		}
768
769
		// Generate the target
770
		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
771
		$target = \OC\Files\Filesystem::normalizePath($target);
772
		$share->setTarget($target);
773
774
		// Pre share event
775
		$event = new GenericEvent($share);
776
		$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

776
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
777
                           dispatch('OCP\Share::preShare', $event);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
'OCP\Share::preShare' of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

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

776
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preShare', $event);
Loading history...
777
		if ($event->isPropagationStopped() && $event->hasArgument('error')) {
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\EventD...:isPropagationStopped() has been deprecated: since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead ( Ignorable by Annotation )

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

777
		if (/** @scrutinizer ignore-deprecated */ $event->isPropagationStopped() && $event->hasArgument('error')) {

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

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

Loading history...
778
			throw new \Exception($event->getArgument('error'));
779
		}
780
781
		$oldShare = $share;
782
		$provider = $this->factory->getProviderForType($share->getShareType());
783
		$share = $provider->create($share);
784
		//reuse the node we already have
785
		$share->setNode($oldShare->getNode());
786
787
		// Reset the target if it is null for the new share
788
		if ($share->getTarget() === '') {
789
			$share->setTarget($target);
790
		}
791
792
		// Post share event
793
		$event = new GenericEvent($share);
794
		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
795
796
		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
797
798
		if ($share->getShareType() === \OCP\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

798
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
799
			$mailSend = $share->getMailSend();
800
			if($mailSend === true) {
801
				$user = $this->userManager->get($share->getSharedWith());
802
				if ($user !== null) {
803
					$emailAddress = $user->getEMailAddress();
804
					if ($emailAddress !== null && $emailAddress !== '') {
805
						$userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
806
						$l = $this->l10nFactory->get('lib', $userLang);
807
						$this->sendMailNotification(
808
							$l,
809
							$share->getNode()->getName(),
810
							$this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
811
							$share->getSharedBy(),
812
							$emailAddress,
813
							$share->getExpirationDate()
814
						);
815
						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
816
					} else {
817
						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
818
					}
819
				} else {
820
					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
821
				}
822
			} else {
823
				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
824
			}
825
		}
826
827
		return $share;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $share returns the type OCP\Share\IShare which is incompatible with the documented return type OCP\Share.
Loading history...
828
	}
829
830
	/**
831
	 * Send mail notifications
832
	 *
833
	 * This method will catch and log mail transmission errors
834
	 *
835
	 * @param IL10N $l Language of the recipient
836
	 * @param string $filename file/folder name
837
	 * @param string $link link to the file/folder
838
	 * @param string $initiator user ID of share sender
839
	 * @param string $shareWith email address of share receiver
840
	 * @param \DateTime|null $expiration
841
	 */
842
	protected function sendMailNotification(IL10N $l,
843
											$filename,
844
											$link,
845
											$initiator,
846
											$shareWith,
847
											\DateTime $expiration = null) {
848
		$initiatorUser = $this->userManager->get($initiator);
849
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
850
851
		$message = $this->mailer->createMessage();
852
853
		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
854
			'filename' => $filename,
855
			'link' => $link,
856
			'initiator' => $initiatorDisplayName,
857
			'expiration' => $expiration,
858
			'shareWith' => $shareWith,
859
		]);
860
861
		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename)));
862
		$emailTemplate->addHeader();
863
		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
864
		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
865
866
		$emailTemplate->addBodyText(
867
			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
868
			$text
869
		);
870
		$emailTemplate->addBodyButton(
871
			$l->t('Open »%s«', [$filename]),
872
			$link
873
		);
874
875
		$message->setTo([$shareWith]);
876
877
		// The "From" contains the sharers name
878
		$instanceName = $this->defaults->getName();
879
		$senderName = $l->t(
880
			'%1$s via %2$s',
881
			[
882
				$initiatorDisplayName,
883
				$instanceName
884
			]
885
		);
886
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
887
888
		// The "Reply-To" is set to the sharer if an mail address is configured
889
		// also the default footer contains a "Do not reply" which needs to be adjusted.
890
		$initiatorEmail = $initiatorUser->getEMailAddress();
891
		if($initiatorEmail !== null) {
892
			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
893
			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
894
		} else {
895
			$emailTemplate->addFooter();
896
		}
897
898
		$message->useTemplate($emailTemplate);
899
		try {
900
			$failedRecipients = $this->mailer->send($message);
901
			if(!empty($failedRecipients)) {
902
				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
903
				return;
904
			}
905
		} catch (\Exception $e) {
906
			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
907
		}
908
	}
909
910
	/**
911
	 * Update a share
912
	 *
913
	 * @param \OCP\Share\IShare $share
914
	 * @return \OCP\Share\IShare The share object
915
	 * @throws \InvalidArgumentException
916
	 */
917
	public function updateShare(\OCP\Share\IShare $share) {
918
		$expirationDateUpdated = false;
919
920
		$this->canShare($share);
921
922
		try {
923
			$originalShare = $this->getShareById($share->getFullId());
924
		} catch (\UnexpectedValueException $e) {
925
			throw new \InvalidArgumentException('Share does not have a full id');
926
		}
927
928
		// We can't change the share type!
929
		if ($share->getShareType() !== $originalShare->getShareType()) {
930
			throw new \InvalidArgumentException('Can’t change share type');
931
		}
932
933
		// We can only change the recipient on user shares
934
		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
935
		    $share->getShareType() !== \OCP\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

935
		    $share->getShareType() !== /** @scrutinizer ignore-deprecated */ \OCP\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...
936
			throw new \InvalidArgumentException('Can only update recipient on user shares');
937
		}
938
939
		// Cannot share with the owner
940
		if ($share->getShareType() === \OCP\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

940
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
941
			$share->getSharedWith() === $share->getShareOwner()) {
942
			throw new \InvalidArgumentException('Can’t share with the share owner');
943
		}
944
945
		$this->generalCreateChecks($share);
946
947
		if ($share->getShareType() === \OCP\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

947
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
948
			$this->userCreateChecks($share);
949
950
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
951
				//Verify the expiration date
952
				$this->validateExpirationDate($share);
953
				$expirationDateUpdated = true;
954
			}
955
		} else if ($share->getShareType() === \OCP\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

955
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
956
			$this->groupCreateChecks($share);
957
958
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
959
				//Verify the expiration date
960
				$this->validateExpirationDate($share);
961
				$expirationDateUpdated = true;
962
			}
963
		} else if ($share->getShareType() === \OCP\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

963
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
964
			$this->linkCreateChecks($share);
965
966
			$this->updateSharePasswordIfNeeded($share, $originalShare);
967
968
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
969
				//Verify the expiration date
970
				$this->validateExpirationDate($share);
971
				$expirationDateUpdated = true;
972
			}
973
		} else if ($share->getShareType() === \OCP\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

973
		} else if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
974
			// The new password is not set again if it is the same as the old
975
			// one, unless when switching from sending by Talk to sending by
976
			// mail.
977
			$plainTextPassword = $share->getPassword();
978
			if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
979
					!($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
980
				$plainTextPassword = null;
981
			}
982
			if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
983
				// If the same password was already sent by mail the recipient
984
				// would already have access to the share without having to call
985
				// the sharer to verify her identity
986
				throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
987
			}
988
		}
989
990
		$this->pathCreateChecks($share->getNode());
991
992
		// Now update the share!
993
		$provider = $this->factory->getProviderForType($share->getShareType());
994
		if ($share->getShareType() === \OCP\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

994
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
995
			$share = $provider->update($share, $plainTextPassword);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $plainTextPassword does not seem to be defined for all execution paths leading up to this point.
Loading history...
Unused Code introduced by
The call to OCP\Share\IShareProvider::update() has too many arguments starting with $plainTextPassword. ( Ignorable by Annotation )

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

995
			/** @scrutinizer ignore-call */ 
996
   $share = $provider->update($share, $plainTextPassword);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
996
		} else {
997
			$share = $provider->update($share);
998
		}
999
1000
		if ($expirationDateUpdated === true) {
1001
			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1002
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1003
				'itemSource' => $share->getNode()->getId(),
1004
				'date' => $share->getExpirationDate(),
1005
				'uidOwner' => $share->getSharedBy(),
1006
			]);
1007
		}
1008
1009
		if ($share->getPassword() !== $originalShare->getPassword()) {
1010
			\OC_Hook::emit(Share::class, 'post_update_password', [
1011
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1012
				'itemSource' => $share->getNode()->getId(),
1013
				'uidOwner' => $share->getSharedBy(),
1014
				'token' => $share->getToken(),
1015
				'disabled' => is_null($share->getPassword()),
1016
			]);
1017
		}
1018
1019
		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1020
			if ($this->userManager->userExists($share->getShareOwner())) {
1021
				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1022
			} else {
1023
				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1024
			}
1025
			\OC_Hook::emit(Share::class, 'post_update_permissions', array(
1026
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1027
				'itemSource' => $share->getNode()->getId(),
1028
				'shareType' => $share->getShareType(),
1029
				'shareWith' => $share->getSharedWith(),
1030
				'uidOwner' => $share->getSharedBy(),
1031
				'permissions' => $share->getPermissions(),
1032
				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1033
			));
1034
		}
1035
1036
		return $share;
1037
	}
1038
1039
	/**
1040
	 * Accept a share.
1041
	 *
1042
	 * @param IShare $share
1043
	 * @param string $recipientId
1044
	 * @return IShare The share object
1045
	 * @throws \InvalidArgumentException
1046
	 * @since 9.0.0
1047
	 */
1048
	public function acceptShare(IShare $share, string $recipientId): IShare {
1049
		[$providerId, ] = $this->splitFullId($share->getFullId());
1050
		$provider = $this->factory->getProvider($providerId);
1051
1052
		if (!method_exists($provider, 'acceptShare')) {
1053
			// TODO FIX ME
1054
			throw new \InvalidArgumentException('Share provider does not support accepting');
1055
		}
1056
		$provider->acceptShare($share, $recipientId);
1057
		$event = new GenericEvent($share);
1058
		$this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
0 ignored issues
show
Bug introduced by
'OCP\Share::postAcceptShare' of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

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

1058
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postAcceptShare', $event);
Loading history...
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

1058
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
1059
                           dispatch('OCP\Share::postAcceptShare', $event);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1059
1060
		return $share;
1061
	}
1062
1063
	/**
1064
	 * Updates the password of the given share if it is not the same as the
1065
	 * password of the original share.
1066
	 *
1067
	 * @param \OCP\Share\IShare $share the share to update its password.
1068
	 * @param \OCP\Share\IShare $originalShare the original share to compare its
1069
	 *        password with.
1070
	 * @return boolean whether the password was updated or not.
1071
	 */
1072
	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
1073
		// Password updated.
1074
		if ($share->getPassword() !== $originalShare->getPassword()) {
1075
			//Verify the password
1076
			$this->verifyPassword($share->getPassword());
1077
1078
			// If a password is set. Hash it!
1079
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
1080
				$share->setPassword($this->hasher->hash($share->getPassword()));
1081
1082
				return true;
1083
			}
1084
		}
1085
1086
		return false;
1087
	}
1088
1089
	/**
1090
	 * Delete all the children of this share
1091
	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1092
	 *
1093
	 * @param \OCP\Share\IShare $share
1094
	 * @return \OCP\Share\IShare[] List of deleted shares
1095
	 */
1096
	protected function deleteChildren(\OCP\Share\IShare $share) {
1097
		$deletedShares = [];
1098
1099
		$provider = $this->factory->getProviderForType($share->getShareType());
1100
1101
		foreach ($provider->getChildren($share) as $child) {
0 ignored issues
show
Bug introduced by
The method getChildren() does not exist on OCP\Share\IShareProvider. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Share\IShareProvider. ( Ignorable by Annotation )

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

1101
		foreach ($provider->/** @scrutinizer ignore-call */ getChildren($share) as $child) {
Loading history...
1102
			$deletedChildren = $this->deleteChildren($child);
1103
			$deletedShares = array_merge($deletedShares, $deletedChildren);
1104
1105
			$provider->delete($child);
1106
			$deletedShares[] = $child;
1107
		}
1108
1109
		return $deletedShares;
1110
	}
1111
1112
	/**
1113
	 * Delete a share
1114
	 *
1115
	 * @param \OCP\Share\IShare $share
1116
	 * @throws ShareNotFound
1117
	 * @throws \InvalidArgumentException
1118
	 */
1119
	public function deleteShare(\OCP\Share\IShare $share) {
1120
1121
		try {
1122
			$share->getFullId();
1123
		} catch (\UnexpectedValueException $e) {
1124
			throw new \InvalidArgumentException('Share does not have a full id');
1125
		}
1126
1127
		$event = new GenericEvent($share);
1128
		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

1128
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
1129
                           dispatch('OCP\Share::preUnshare', $event);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
'OCP\Share::preUnshare' of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

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

1128
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preUnshare', $event);
Loading history...
1129
1130
		// Get all children and delete them as well
1131
		$deletedShares = $this->deleteChildren($share);
1132
1133
		// Do the actual delete
1134
		$provider = $this->factory->getProviderForType($share->getShareType());
1135
		$provider->delete($share);
1136
1137
		// All the deleted shares caused by this delete
1138
		$deletedShares[] = $share;
1139
1140
		// Emit post hook
1141
		$event->setArgument('deletedShares', $deletedShares);
1142
		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1143
	}
1144
1145
1146
	/**
1147
	 * Unshare a file as the recipient.
1148
	 * This can be different from a regular delete for example when one of
1149
	 * the users in a groups deletes that share. But the provider should
1150
	 * handle this.
1151
	 *
1152
	 * @param \OCP\Share\IShare $share
1153
	 * @param string $recipientId
1154
	 */
1155
	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
1156
		list($providerId, ) = $this->splitFullId($share->getFullId());
1157
		$provider = $this->factory->getProvider($providerId);
1158
1159
		$provider->deleteFromSelf($share, $recipientId);
1160
		$event = new GenericEvent($share);
1161
		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
0 ignored issues
show
Bug introduced by
'OCP\Share::postUnshareFromSelf' of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

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

1161
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postUnshareFromSelf', $event);
Loading history...
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

1161
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
1162
                           dispatch('OCP\Share::postUnshareFromSelf', $event);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1162
	}
1163
1164
	public function restoreShare(IShare $share, string $recipientId): IShare {
1165
		list($providerId, ) = $this->splitFullId($share->getFullId());
1166
		$provider = $this->factory->getProvider($providerId);
1167
1168
		return $provider->restore($share, $recipientId);
1169
	}
1170
1171
	/**
1172
	 * @inheritdoc
1173
	 */
1174
	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1175
		if ($share->getShareType() === \OCP\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

1175
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
1176
			throw new \InvalidArgumentException('Can’t change target of link share');
1177
		}
1178
1179
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
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

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

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...
1180
			throw new \InvalidArgumentException('Invalid recipient');
1181
		}
1182
1183
		if ($share->getShareType() === \OCP\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

1183
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
1184
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1185
			if (is_null($sharedWith)) {
1186
				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1187
			}
1188
			$recipient = $this->userManager->get($recipientId);
1189
			if (!$sharedWith->inGroup($recipient)) {
1190
				throw new \InvalidArgumentException('Invalid recipient');
1191
			}
1192
		}
1193
1194
		list($providerId, ) = $this->splitFullId($share->getFullId());
1195
		$provider = $this->factory->getProvider($providerId);
1196
1197
		$provider->move($share, $recipientId);
1198
	}
1199
1200
	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1201
		$providers = $this->factory->getAllProviders();
1202
1203
		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1204
			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1205
			foreach ($newShares as $fid => $data) {
1206
				if (!isset($shares[$fid])) {
1207
					$shares[$fid] = [];
1208
				}
1209
1210
				$shares[$fid] = array_merge($shares[$fid], $data);
0 ignored issues
show
Bug introduced by
$data of type OCP\Share\IShare 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

1210
				$shares[$fid] = array_merge($shares[$fid], /** @scrutinizer ignore-type */ $data);
Loading history...
1211
			}
1212
			return $shares;
1213
		}, []);
1214
	}
1215
1216
	/**
1217
	 * @inheritdoc
1218
	 */
1219
	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1220
		if ($path !== null &&
1221
				!($path instanceof \OCP\Files\File) &&
1222
				!($path instanceof \OCP\Files\Folder)) {
1223
			throw new \InvalidArgumentException('invalid path');
1224
		}
1225
1226
		try {
1227
			$provider = $this->factory->getProviderForType($shareType);
1228
		} catch (ProviderException $e) {
1229
			return [];
1230
		}
1231
1232
		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1233
1234
		/*
1235
		 * Work around so we don't return expired shares but still follow
1236
		 * proper pagination.
1237
		 */
1238
1239
		$shares2 = [];
1240
1241
		while(true) {
1242
			$added = 0;
1243
			foreach ($shares as $share) {
1244
1245
				try {
1246
					$this->checkExpireDate($share);
1247
				} catch (ShareNotFound $e) {
1248
					//Ignore since this basically means the share is deleted
1249
					continue;
1250
				}
1251
1252
				$added++;
1253
				$shares2[] = $share;
1254
1255
				if (count($shares2) === $limit) {
1256
					break;
1257
				}
1258
			}
1259
1260
			// If we did not fetch more shares than the limit then there are no more shares
1261
			if (count($shares) < $limit) {
1262
				break;
1263
			}
1264
1265
			if (count($shares2) === $limit) {
1266
				break;
1267
			}
1268
1269
			// If there was no limit on the select we are done
1270
			if ($limit === -1) {
1271
				break;
1272
			}
1273
1274
			$offset += $added;
1275
1276
			// Fetch again $limit shares
1277
			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1278
1279
			// No more shares means we are done
1280
			if (empty($shares)) {
1281
				break;
1282
			}
1283
		}
1284
1285
		$shares = $shares2;
1286
1287
		return $shares;
1288
	}
1289
1290
	/**
1291
	 * @inheritdoc
1292
	 */
1293
	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1294
		try {
1295
			$provider = $this->factory->getProviderForType($shareType);
1296
		} catch (ProviderException $e) {
1297
			return [];
1298
		}
1299
1300
		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1301
1302
		// remove all shares which are already expired
1303
		foreach ($shares as $key => $share) {
1304
			try {
1305
				$this->checkExpireDate($share);
1306
			} catch (ShareNotFound $e) {
1307
				unset($shares[$key]);
1308
			}
1309
		}
1310
1311
		return $shares;
1312
	}
1313
1314
	/**
1315
	 * @inheritdoc
1316
	 */
1317
	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1318
		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1319
1320
		// Only get deleted shares
1321
		$shares = array_filter($shares, function(IShare $share) {
1322
			return $share->getPermissions() === 0;
1323
		});
1324
1325
		// Only get shares where the owner still exists
1326
		$shares = array_filter($shares, function (IShare $share) {
1327
			return $this->userManager->userExists($share->getShareOwner());
1328
		});
1329
1330
		return $shares;
1331
	}
1332
1333
	/**
1334
	 * @inheritdoc
1335
	 */
1336
	public function getShareById($id, $recipient = null) {
1337
		if ($id === null) {
1338
			throw new ShareNotFound();
1339
		}
1340
1341
		list($providerId, $id) = $this->splitFullId($id);
1342
1343
		try {
1344
			$provider = $this->factory->getProvider($providerId);
1345
		} catch (ProviderException $e) {
1346
			throw new ShareNotFound();
1347
		}
1348
1349
		$share = $provider->getShareById($id, $recipient);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $id of OCP\Share\IShareProvider::getShareById(). ( Ignorable by Annotation )

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

1349
		$share = $provider->getShareById(/** @scrutinizer ignore-type */ $id, $recipient);
Loading history...
1350
1351
		$this->checkExpireDate($share);
1352
1353
		return $share;
1354
	}
1355
1356
	/**
1357
	 * Get all the shares for a given path
1358
	 *
1359
	 * @param \OCP\Files\Node $path
1360
	 * @param int $page
1361
	 * @param int $perPage
1362
	 *
1363
	 * @return Share[]
1364
	 */
1365
	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
0 ignored issues
show
Unused Code introduced by
The parameter $page is not used and could be removed. ( Ignorable by Annotation )

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

1365
	public function getSharesByPath(\OCP\Files\Node $path, /** @scrutinizer ignore-unused */ $page=0, $perPage=50) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed. ( Ignorable by Annotation )

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

1365
	public function getSharesByPath(/** @scrutinizer ignore-unused */ \OCP\Files\Node $path, $page=0, $perPage=50) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $perPage is not used and could be removed. ( Ignorable by Annotation )

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

1365
	public function getSharesByPath(\OCP\Files\Node $path, $page=0, /** @scrutinizer ignore-unused */ $perPage=50) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1366
		return [];
1367
	}
1368
1369
	/**
1370
	 * Get the share by token possible with password
1371
	 *
1372
	 * @param string $token
1373
	 * @return Share
1374
	 *
1375
	 * @throws ShareNotFound
1376
	 */
1377
	public function getShareByToken($token) {
1378
		// tokens can't be valid local user names
1379
		if ($this->userManager->userExists($token)) {
1380
			throw new ShareNotFound();
1381
		}
1382
		$share = null;
1383
		try {
1384
			if($this->shareApiAllowLinks()) {
1385
				$provider = $this->factory->getProviderForType(\OCP\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

1385
				$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1386
				$share = $provider->getShareByToken($token);
1387
			}
1388
		} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1389
		} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1390
		}
1391
1392
1393
		// If it is not a link share try to fetch a federated share by token
1394
		if ($share === null) {
1395
			try {
1396
				$provider = $this->factory->getProviderForType(\OCP\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

1396
				$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1397
				$share = $provider->getShareByToken($token);
1398
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1399
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1400
			}
1401
		}
1402
1403
		// If it is not a link share try to fetch a mail share by token
1404
		if ($share === null && $this->shareProviderExists(\OCP\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

1404
		if ($share === null && $this->shareProviderExists(/** @scrutinizer ignore-deprecated */ \OCP\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...
1405
			try {
1406
				$provider = $this->factory->getProviderForType(\OCP\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
				$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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 = $provider->getShareByToken($token);
1408
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1409
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1410
			}
1411
		}
1412
1413
		if ($share === null && $this->shareProviderExists(\OCP\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

1413
		if ($share === null && $this->shareProviderExists(/** @scrutinizer ignore-deprecated */ \OCP\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...
1414
			try {
1415
				$provider = $this->factory->getProviderForType(\OCP\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

1415
				$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1416
				$share = $provider->getShareByToken($token);
1417
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1418
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1419
			}
1420
		}
1421
1422
		if ($share === null && $this->shareProviderExists(\OCP\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

1422
		if ($share === null && $this->shareProviderExists(/** @scrutinizer ignore-deprecated */ \OCP\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...
1423
			try {
1424
				$provider = $this->factory->getProviderForType(\OCP\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

1424
				$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1425
				$share = $provider->getShareByToken($token);
1426
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1427
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1428
			}
1429
		}
1430
1431
		if ($share === null) {
1432
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1433
		}
1434
1435
		$this->checkExpireDate($share);
1436
1437
		/*
1438
		 * Reduce the permissions for link shares if public upload is not enabled
1439
		 */
1440
		if ($share->getShareType() === \OCP\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

1440
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\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...
1441
			!$this->shareApiLinkAllowPublicUpload()) {
1442
			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1443
		}
1444
1445
		return $share;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $share returns the type OCP\Share\IShare which is incompatible with the documented return type OCP\Share.
Loading history...
1446
	}
1447
1448
	protected function checkExpireDate($share) {
1449
		if ($share->isExpired()) {
1450
			$this->deleteShare($share);
1451
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1452
		}
1453
1454
	}
1455
1456
	/**
1457
	 * Verify the password of a public share
1458
	 *
1459
	 * @param \OCP\Share\IShare $share
1460
	 * @param string $password
1461
	 * @return bool
1462
	 */
1463
	public function checkPassword(\OCP\Share\IShare $share, $password) {
1464
		$passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1465
							 || $share->getShareType() !== IShare::TYPE_EMAIL
1466
							 || $share->getShareType() !== IShare::TYPE_CIRCLE;
1467
		if (!$passwordProtected) {
1468
			//TODO maybe exception?
1469
			return false;
1470
		}
1471
1472
		if ($password === null || $share->getPassword() === null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() === null is always false.
Loading history...
1473
			return false;
1474
		}
1475
1476
		$newHash = '';
1477
		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1478
			return false;
1479
		}
1480
1481
		if (!empty($newHash)) {
1482
			$share->setPassword($newHash);
1483
			$provider = $this->factory->getProviderForType($share->getShareType());
1484
			$provider->update($share);
1485
		}
1486
1487
		return true;
1488
	}
1489
1490
	/**
1491
	 * @inheritdoc
1492
	 */
1493
	public function userDeleted($uid) {
1494
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
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

1494
		$types = [/** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\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...
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

1494
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, /** @scrutinizer ignore-deprecated */ \OCP\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...
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

1494
		$types = [\OCP\Share::SHARE_TYPE_USER, /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\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...
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

1494
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\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...
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

1494
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_REMOTE, \OCP\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...
1495
1496
		foreach ($types as $type) {
1497
			try {
1498
				$provider = $this->factory->getProviderForType($type);
1499
			} catch (ProviderException $e) {
1500
				continue;
1501
			}
1502
			$provider->userDeleted($uid, $type);
1503
		}
1504
	}
1505
1506
	/**
1507
	 * @inheritdoc
1508
	 */
1509
	public function groupDeleted($gid) {
1510
		$provider = $this->factory->getProviderForType(\OCP\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

1510
		$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1511
		$provider->groupDeleted($gid);
1512
	}
1513
1514
	/**
1515
	 * @inheritdoc
1516
	 */
1517
	public function userDeletedFromGroup($uid, $gid) {
1518
		$provider = $this->factory->getProviderForType(\OCP\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

1518
		$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\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...
1519
		$provider->userDeletedFromGroup($uid, $gid);
1520
	}
1521
1522
	/**
1523
	 * Get access list to a path. This means
1524
	 * all the users that can access a given path.
1525
	 *
1526
	 * Consider:
1527
	 * -root
1528
	 * |-folder1 (23)
1529
	 *  |-folder2 (32)
1530
	 *   |-fileA (42)
1531
	 *
1532
	 * fileA is shared with user1 and user1@server1
1533
	 * folder2 is shared with group2 (user4 is a member of group2)
1534
	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1535
	 *
1536
	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1537
	 * [
1538
	 *  users  => [
1539
	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1540
	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1541
	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1542
	 *  ],
1543
	 *  remote => [
1544
	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1545
	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1546
	 *  ],
1547
	 *  public => bool
1548
	 *  mail => bool
1549
	 * ]
1550
	 *
1551
	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1552
	 * [
1553
	 *  users  => ['user1', 'user2', 'user4'],
1554
	 *  remote => bool,
1555
	 *  public => bool
1556
	 *  mail => bool
1557
	 * ]
1558
	 *
1559
	 * This is required for encryption/activity
1560
	 *
1561
	 * @param \OCP\Files\Node $path
1562
	 * @param bool $recursive Should we check all parent folders as well
1563
	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1564
	 * @return array
1565
	 */
1566
	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1567
		$owner = $path->getOwner();
1568
1569
		if ($owner === null) {
1570
			return [];
1571
		}
1572
1573
		$owner = $owner->getUID();
1574
1575
		if ($currentAccess) {
1576
			$al = ['users' => [], 'remote' => [], 'public' => false];
1577
		} else {
1578
			$al = ['users' => [], 'remote' => false, 'public' => false];
1579
		}
1580
		if (!$this->userManager->userExists($owner)) {
1581
			return $al;
1582
		}
1583
1584
		//Get node for the owner and correct the owner in case of external storages
1585
		$userFolder = $this->rootFolder->getUserFolder($owner);
1586
		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1587
			$nodes = $userFolder->getById($path->getId());
1588
			$path = array_shift($nodes);
1589
			if ($path->getOwner() === null) {
1590
				return [];
1591
			}
1592
			$owner = $path->getOwner()->getUID();
1593
		}
1594
1595
		$providers = $this->factory->getAllProviders();
1596
1597
		/** @var Node[] $nodes */
1598
		$nodes = [];
1599
1600
1601
		if ($currentAccess) {
1602
			$ownerPath = $path->getPath();
1603
			$ownerPath = explode('/', $ownerPath, 4);
1604
			if (count($ownerPath) < 4) {
1605
				$ownerPath = '';
1606
			} else {
1607
				$ownerPath = $ownerPath[3];
1608
			}
1609
			$al['users'][$owner] = [
1610
				'node_id' => $path->getId(),
1611
				'node_path' => '/' . $ownerPath,
1612
			];
1613
		} else {
1614
			$al['users'][] = $owner;
1615
		}
1616
1617
		// Collect all the shares
1618
		while ($path->getPath() !== $userFolder->getPath()) {
1619
			$nodes[] = $path;
1620
			if (!$recursive) {
1621
				break;
1622
			}
1623
			$path = $path->getParent();
1624
		}
1625
1626
		foreach ($providers as $provider) {
1627
			$tmp = $provider->getAccessList($nodes, $currentAccess);
1628
1629
			foreach ($tmp as $k => $v) {
1630
				if (isset($al[$k])) {
1631
					if (is_array($al[$k])) {
1632
						if ($currentAccess) {
1633
							$al[$k] += $v;
1634
						} else {
1635
							$al[$k] = array_merge($al[$k], $v);
1636
							$al[$k] = array_unique($al[$k]);
1637
							$al[$k] = array_values($al[$k]);
1638
						}
1639
					} else {
1640
						$al[$k] = $al[$k] || $v;
1641
					}
1642
				} else {
1643
					$al[$k] = $v;
1644
				}
1645
			}
1646
		}
1647
1648
		return $al;
1649
	}
1650
1651
	/**
1652
	 * Create a new share
1653
	 * @return \OCP\Share\IShare
1654
	 */
1655
	public function newShare() {
1656
		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1657
	}
1658
1659
	/**
1660
	 * Is the share API enabled
1661
	 *
1662
	 * @return bool
1663
	 */
1664
	public function shareApiEnabled() {
1665
		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1666
	}
1667
1668
	/**
1669
	 * Is public link sharing enabled
1670
	 *
1671
	 * @return bool
1672
	 */
1673
	public function shareApiAllowLinks() {
1674
		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1675
	}
1676
1677
	/**
1678
	 * Is password on public link requires
1679
	 *
1680
	 * @return bool
1681
	 */
1682
	public function shareApiLinkEnforcePassword() {
1683
		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1684
	}
1685
1686
	/**
1687
	 * Is default link expire date enabled
1688
	 *
1689
	 * @return bool
1690
	 */
1691
	public function shareApiLinkDefaultExpireDate() {
1692
		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1693
	}
1694
1695
	/**
1696
	 * Is default link expire date enforced
1697
	 *`
1698
	 * @return bool
1699
	 */
1700
	public function shareApiLinkDefaultExpireDateEnforced() {
1701
		return $this->shareApiLinkDefaultExpireDate() &&
1702
			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1703
	}
1704
1705
1706
	/**
1707
	 * Number of default link expire days
1708
	 * @return int
1709
	 */
1710
	public function shareApiLinkDefaultExpireDays() {
1711
		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1712
	}
1713
1714
	/**
1715
	 * Is default internal expire date enabled
1716
	 *
1717
	 * @return bool
1718
	 */
1719
	public function shareApiInternalDefaultExpireDate(): bool {
1720
		return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1721
	}
1722
1723
	/**
1724
	 * Is default expire date enforced
1725
	 *`
1726
	 * @return bool
1727
	 */
1728
	public function shareApiInternalDefaultExpireDateEnforced(): bool {
1729
		return $this->shareApiInternalDefaultExpireDate() &&
1730
			$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1731
	}
1732
1733
1734
	/**
1735
	 * Number of default expire days
1736
	 * @return int
1737
	 */
1738
	public function shareApiInternalDefaultExpireDays(): int {
1739
		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1740
	}
1741
1742
	/**
1743
	 * Allow public upload on link shares
1744
	 *
1745
	 * @return bool
1746
	 */
1747
	public function shareApiLinkAllowPublicUpload() {
1748
		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1749
	}
1750
1751
	/**
1752
	 * check if user can only share with group members
1753
	 * @return bool
1754
	 */
1755
	public function shareWithGroupMembersOnly() {
1756
		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1757
	}
1758
1759
	/**
1760
	 * Check if users can share with groups
1761
	 * @return bool
1762
	 */
1763
	public function allowGroupSharing() {
1764
		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1765
	}
1766
1767
	/**
1768
	 * Copied from \OC_Util::isSharingDisabledForUser
1769
	 *
1770
	 * TODO: Deprecate fuction from OC_Util
1771
	 *
1772
	 * @param string $userId
1773
	 * @return bool
1774
	 */
1775
	public function sharingDisabledForUser($userId) {
1776
		if ($userId === null) {
0 ignored issues
show
introduced by
The condition $userId === null is always false.
Loading history...
1777
			return false;
1778
		}
1779
1780
		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1781
			return $this->sharingDisabledForUsersCache[$userId];
1782
		}
1783
1784
		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1785
			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1786
			$excludedGroups = json_decode($groupsList);
1787
			if (is_null($excludedGroups)) {
1788
				$excludedGroups = explode(',', $groupsList);
1789
				$newValue = json_encode($excludedGroups);
1790
				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1791
			}
1792
			$user = $this->userManager->get($userId);
1793
			$usersGroups = $this->groupManager->getUserGroupIds($user);
1794
			if (!empty($usersGroups)) {
1795
				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1796
				// if the user is only in groups which are disabled for sharing then
1797
				// sharing is also disabled for the user
1798
				if (empty($remainingGroups)) {
1799
					$this->sharingDisabledForUsersCache[$userId] = true;
1800
					return true;
1801
				}
1802
			}
1803
		}
1804
1805
		$this->sharingDisabledForUsersCache[$userId] = false;
1806
		return false;
1807
	}
1808
1809
	/**
1810
	 * @inheritdoc
1811
	 */
1812
	public function outgoingServer2ServerSharesAllowed() {
1813
		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1814
	}
1815
1816
	/**
1817
	 * @inheritdoc
1818
	 */
1819
	public function outgoingServer2ServerGroupSharesAllowed() {
1820
		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1821
	}
1822
1823
	/**
1824
	 * @inheritdoc
1825
	 */
1826
	public function shareProviderExists($shareType) {
1827
		try {
1828
			$this->factory->getProviderForType($shareType);
1829
		} catch (ProviderException $e) {
1830
			return false;
1831
		}
1832
1833
		return true;
1834
	}
1835
1836
	public function getAllShares(): iterable {
1837
		$providers = $this->factory->getAllProviders();
1838
1839
		foreach ($providers as $provider) {
1840
			yield from $provider->getAllShares();
1841
		}
1842
	}
1843
}
1844