Passed
Push — master ( 6b97f6...a6ae80 )
by Blizzz
13:11 queued 11s
created

Manager::validateExpirationDateInternal()   B

Complexity

Conditions 11
Paths 49

Size

Total Lines 60
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 36
c 1
b 0
f 0
dl 0
loc 60
rs 7.3166
cc 11
nc 49
nop 1

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 Daniel Calviño Sánchez <[email protected]>
9
 * @author Jan-Christoph Borchardt <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Julius Härtl <[email protected]>
12
 * @author Lukas Reschke <[email protected]>
13
 * @author Maxence Lange <[email protected]>
14
 * @author Maxence Lange <[email protected]>
15
 * @author Morris Jobke <[email protected]>
16
 * @author Pauli Järvinen <[email protected]>
17
 * @author Robin Appelman <[email protected]>
18
 * @author Roeland Jago Douma <[email protected]>
19
 * @author Stephan Müller <[email protected]>
20
 * @author Vincent Petry <[email protected]>
21
 *
22
 * @license AGPL-3.0
23
 *
24
 * This code is free software: you can redistribute it and/or modify
25
 * it under the terms of the GNU Affero General Public License, version 3,
26
 * as published by the Free Software Foundation.
27
 *
28
 * This program is distributed in the hope that it will be useful,
29
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
 * GNU Affero General Public License for more details.
32
 *
33
 * You should have received a copy of the GNU Affero General Public License, version 3,
34
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
35
 *
36
 */
37
38
namespace OC\Share20;
39
40
use OC\Cache\CappedMemoryCache;
41
use OC\Files\Mount\MoveableMount;
42
use OC\HintException;
43
use OC\Share20\Exception\ProviderException;
44
use OCP\Files\File;
45
use OCP\Files\Folder;
46
use OCP\Files\IRootFolder;
47
use OCP\Files\Mount\IMountManager;
48
use OCP\Files\Node;
49
use OCP\IConfig;
50
use OCP\IGroupManager;
51
use OCP\IL10N;
52
use OCP\ILogger;
53
use OCP\IURLGenerator;
54
use OCP\IUser;
55
use OCP\IUserManager;
56
use OCP\L10N\IFactory;
57
use OCP\Mail\IMailer;
58
use OCP\Security\Events\ValidatePasswordPolicyEvent;
59
use OCP\Security\IHasher;
60
use OCP\Security\ISecureRandom;
61
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...
62
use OCP\Share\Exceptions\GenericShareException;
63
use OCP\Share\Exceptions\ShareNotFound;
64
use OCP\Share\IManager;
65
use OCP\Share\IProviderFactory;
66
use OCP\Share\IShare;
67
use OCP\Share\IShareProvider;
68
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
69
use Symfony\Component\EventDispatcher\GenericEvent;
70
71
/**
72
 * This class is the communication hub for all sharing related operations.
73
 */
74
class Manager implements IManager {
75
76
	/** @var IProviderFactory */
77
	private $factory;
78
	/** @var ILogger */
79
	private $logger;
80
	/** @var IConfig */
81
	private $config;
82
	/** @var ISecureRandom */
83
	private $secureRandom;
84
	/** @var IHasher */
85
	private $hasher;
86
	/** @var IMountManager */
87
	private $mountManager;
88
	/** @var IGroupManager */
89
	private $groupManager;
90
	/** @var IL10N */
91
	private $l;
92
	/** @var IFactory */
93
	private $l10nFactory;
94
	/** @var IUserManager */
95
	private $userManager;
96
	/** @var IRootFolder */
97
	private $rootFolder;
98
	/** @var CappedMemoryCache */
99
	private $sharingDisabledForUsersCache;
100
	/** @var EventDispatcherInterface */
101
	private $eventDispatcher;
102
	/** @var LegacyHooks */
103
	private $legacyHooks;
104
	/** @var IMailer */
105
	private $mailer;
106
	/** @var IURLGenerator */
107
	private $urlGenerator;
108
	/** @var \OC_Defaults */
109
	private $defaults;
110
111
112
	/**
113
	 * Manager constructor.
114
	 *
115
	 * @param ILogger $logger
116
	 * @param IConfig $config
117
	 * @param ISecureRandom $secureRandom
118
	 * @param IHasher $hasher
119
	 * @param IMountManager $mountManager
120
	 * @param IGroupManager $groupManager
121
	 * @param IL10N $l
122
	 * @param IFactory $l10nFactory
123
	 * @param IProviderFactory $factory
124
	 * @param IUserManager $userManager
125
	 * @param IRootFolder $rootFolder
126
	 * @param EventDispatcherInterface $eventDispatcher
127
	 * @param IMailer $mailer
128
	 * @param IURLGenerator $urlGenerator
129
	 * @param \OC_Defaults $defaults
130
	 */
131
	public function __construct(
132
			ILogger $logger,
133
			IConfig $config,
134
			ISecureRandom $secureRandom,
135
			IHasher $hasher,
136
			IMountManager $mountManager,
137
			IGroupManager $groupManager,
138
			IL10N $l,
139
			IFactory $l10nFactory,
140
			IProviderFactory $factory,
141
			IUserManager $userManager,
142
			IRootFolder $rootFolder,
143
			EventDispatcherInterface $eventDispatcher,
144
			IMailer $mailer,
145
			IURLGenerator $urlGenerator,
146
			\OC_Defaults $defaults
147
	) {
148
		$this->logger = $logger;
149
		$this->config = $config;
150
		$this->secureRandom = $secureRandom;
151
		$this->hasher = $hasher;
152
		$this->mountManager = $mountManager;
153
		$this->groupManager = $groupManager;
154
		$this->l = $l;
155
		$this->l10nFactory = $l10nFactory;
156
		$this->factory = $factory;
157
		$this->userManager = $userManager;
158
		$this->rootFolder = $rootFolder;
159
		$this->eventDispatcher = $eventDispatcher;
160
		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
161
		$this->legacyHooks = new LegacyHooks($this->eventDispatcher);
162
		$this->mailer = $mailer;
163
		$this->urlGenerator = $urlGenerator;
164
		$this->defaults = $defaults;
165
	}
166
167
	/**
168
	 * Convert from a full share id to a tuple (providerId, shareId)
169
	 *
170
	 * @param string $id
171
	 * @return string[]
172
	 */
173
	private function splitFullId($id) {
174
		return explode(':', $id, 2);
175
	}
176
177
	/**
178
	 * Verify if a password meets all requirements
179
	 *
180
	 * @param string $password
181
	 * @throws \Exception
182
	 */
183
	protected function verifyPassword($password) {
184
		if ($password === null) {
0 ignored issues
show
introduced by
The condition $password === null is always false.
Loading history...
185
			// No password is set, check if this is allowed.
186
			if ($this->shareApiLinkEnforcePassword()) {
187
				throw new \InvalidArgumentException('Passwords are enforced for link shares');
188
			}
189
190
			return;
191
		}
192
193
		// Let others verify the password
194
		try {
195
			$this->eventDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
196
		} catch (HintException $e) {
197
			throw new \Exception($e->getHint());
198
		}
199
	}
200
201
	/**
202
	 * Check for generic requirements before creating a share
203
	 *
204
	 * @param \OCP\Share\IShare $share
205
	 * @throws \InvalidArgumentException
206
	 * @throws GenericShareException
207
	 *
208
	 * @suppress PhanUndeclaredClassMethod
209
	 */
210
	protected function generalCreateChecks(\OCP\Share\IShare $share) {
211
		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

211
		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...
212
			// We expect a valid user as sharedWith for user shares
213
			if (!$this->userManager->userExists($share->getSharedWith())) {
214
				throw new \InvalidArgumentException('SharedWith is not a valid user');
215
			}
216
		} 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

216
		} 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...
217
			// We expect a valid group as sharedWith for group shares
218
			if (!$this->groupManager->groupExists($share->getSharedWith())) {
219
				throw new \InvalidArgumentException('SharedWith is not a valid group');
220
			}
221
		} 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

221
		} 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...
222
			if ($share->getSharedWith() !== null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() !== null is always true.
Loading history...
223
				throw new \InvalidArgumentException('SharedWith should be empty');
224
			}
225
		} 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

225
		} 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...
226
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
227
				throw new \InvalidArgumentException('SharedWith should not be empty');
228
			}
229
		}  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

229
		}  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...
230
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
231
				throw new \InvalidArgumentException('SharedWith should not be empty');
232
			}
233
		} 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

233
		} 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...
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_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

237
		} 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...
238
			$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...
239
			if ($circle === null) {
240
				throw new \InvalidArgumentException('SharedWith is not a valid circle');
241
			}
242
		} 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

242
		} 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...
243
		} else {
244
			// We can't handle other types yet
245
			throw new \InvalidArgumentException('unknown share type');
246
		}
247
248
		// Verify the initiator of the share is set
249
		if ($share->getSharedBy() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedBy() === null is always false.
Loading history...
250
			throw new \InvalidArgumentException('SharedBy should be set');
251
		}
252
253
		// Cannot share with yourself
254
		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

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

303
			$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...
304
			$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

304
			$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...
305
			$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

305
			$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...
306
			$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

306
			$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...
307
308
			/** @var \OCP\Share\IShare[] $incomingShares */
309
			if (!empty($incomingShares)) {
310
				foreach ($incomingShares as $incomingShare) {
311
					$permissions |= $incomingShare->getPermissions();
312
				}
313
			}
314
		} else {
315
			/*
316
			 * Quick fix for #23536
317
			 * Non moveable mount points do not have update and delete permissions
318
			 * while we 'most likely' do have that on the storage.
319
			 */
320
			$permissions = $share->getNode()->getPermissions();
321
			if (!($mount instanceof MoveableMount)) {
322
				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
323
			}
324
		}
325
326
		// Check that we do not share with more permissions than we have
327
		if ($share->getPermissions() & ~$permissions) {
328
			$message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
329
			throw new GenericShareException($message_t, $message_t, 404);
330
		}
331
332
333
		// Check that read permissions are always set
334
		// Link shares are allowed to have no read permissions to allow upload to hidden folders
335
		$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

335
		$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...
336
			|| $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

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

523
		$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...
524
		$existingShares = $provider->getSharesByPath($share->getNode());
525
		foreach($existingShares as $existingShare) {
526
			// Ignore if it is the same share
527
			try {
528
				if ($existingShare->getFullId() === $share->getFullId()) {
529
					continue;
530
				}
531
			} catch (\UnexpectedValueException $e) {
532
				//Shares are not identical
533
			}
534
535
			// Identical share already existst
536
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
537
				throw new \Exception('Path is already shared with this user');
538
			}
539
540
			// The share is already shared with this user via a group share
541
			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

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

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

708
		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...
709
			$this->userCreateChecks($share);
710
711
			//Verify the expiration date
712
			$share = $this->validateExpirationDateInternal($share);
713
714
		} 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

714
		} 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...
715
			$this->groupCreateChecks($share);
716
717
			//Verify the expiration date
718
			$share = $this->validateExpirationDateInternal($share);
719
720
		} 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

720
		} 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...
721
			$this->linkCreateChecks($share);
722
			$this->setLinkParent($share);
723
724
			/*
725
			 * For now ignore a set token.
726
			 */
727
			$share->setToken(
728
				$this->secureRandom->generate(
729
					\OC\Share\Constants::TOKEN_LENGTH,
730
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
731
				)
732
			);
733
734
			//Verify the expiration date
735
			$share = $this->validateExpirationDate($share);
736
737
			//Verify the password
738
			$this->verifyPassword($share->getPassword());
739
740
			// If a password is set. Hash it!
741
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
742
				$share->setPassword($this->hasher->hash($share->getPassword()));
743
			}
744
		} 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

744
		} 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...
745
			$share->setToken(
746
				$this->secureRandom->generate(
747
					\OC\Share\Constants::TOKEN_LENGTH,
748
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
749
				)
750
			);
751
		}
752
753
		// Cannot share with the owner
754
		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

754
		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...
755
			$share->getSharedWith() === $share->getShareOwner()) {
756
			throw new \InvalidArgumentException('Can’t share with the share owner');
757
		}
758
759
		// Generate the target
760
		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
761
		$target = \OC\Files\Filesystem::normalizePath($target);
762
		$share->setTarget($target);
763
764
		// Pre share event
765
		$event = new GenericEvent($share);
766
		$this->eventDispatcher->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

766
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
767
                          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

766
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preShare', $event);
Loading history...
767
		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

767
		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...
768
			throw new \Exception($event->getArgument('error'));
769
		}
770
771
		$oldShare = $share;
772
		$provider = $this->factory->getProviderForType($share->getShareType());
773
		$share = $provider->create($share);
774
		//reuse the node we already have
775
		$share->setNode($oldShare->getNode());
776
777
		// Post share event
778
		$event = new GenericEvent($share);
779
		$this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
780
781
		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

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

918
		    $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...
919
			throw new \InvalidArgumentException('Can only update recipient on user shares');
920
		}
921
922
		// Cannot share with the owner
923
		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

923
		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...
924
			$share->getSharedWith() === $share->getShareOwner()) {
925
			throw new \InvalidArgumentException('Can’t share with the share owner');
926
		}
927
928
		$this->generalCreateChecks($share);
929
930
		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

930
		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...
931
			$this->userCreateChecks($share);
932
933
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
934
				//Verify the expiration date
935
				$this->validateExpirationDate($share);
936
				$expirationDateUpdated = true;
937
			}
938
		} 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

938
		} 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...
939
			$this->groupCreateChecks($share);
940
941
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
942
				//Verify the expiration date
943
				$this->validateExpirationDate($share);
944
				$expirationDateUpdated = true;
945
			}
946
		} 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

946
		} 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...
947
			$this->linkCreateChecks($share);
948
949
			$this->updateSharePasswordIfNeeded($share, $originalShare);
950
951
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
952
				//Verify the expiration date
953
				$this->validateExpirationDate($share);
954
				$expirationDateUpdated = true;
955
			}
956
		} 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

956
		} 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...
957
			// The new password is not set again if it is the same as the old
958
			// one, unless when switching from sending by Talk to sending by
959
			// mail.
960
			$plainTextPassword = $share->getPassword();
961
			if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
962
					!($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
963
				$plainTextPassword = null;
964
			}
965
			if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
966
				// If the same password was already sent by mail the recipient
967
				// would already have access to the share without having to call
968
				// the sharer to verify her identity
969
				throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
970
			}
971
		}
972
973
		$this->pathCreateChecks($share->getNode());
974
975
		// Now update the share!
976
		$provider = $this->factory->getProviderForType($share->getShareType());
977
		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

977
		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...
978
			$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

978
			/** @scrutinizer ignore-call */ 
979
   $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...
979
		} else {
980
			$share = $provider->update($share);
981
		}
982
983
		if ($expirationDateUpdated === true) {
984
			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
985
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
986
				'itemSource' => $share->getNode()->getId(),
987
				'date' => $share->getExpirationDate(),
988
				'uidOwner' => $share->getSharedBy(),
989
			]);
990
		}
991
992
		if ($share->getPassword() !== $originalShare->getPassword()) {
993
			\OC_Hook::emit(Share::class, 'post_update_password', [
994
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
995
				'itemSource' => $share->getNode()->getId(),
996
				'uidOwner' => $share->getSharedBy(),
997
				'token' => $share->getToken(),
998
				'disabled' => is_null($share->getPassword()),
999
			]);
1000
		}
1001
1002
		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1003
			if ($this->userManager->userExists($share->getShareOwner())) {
1004
				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1005
			} else {
1006
				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1007
			}
1008
			\OC_Hook::emit(Share::class, 'post_update_permissions', array(
1009
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1010
				'itemSource' => $share->getNode()->getId(),
1011
				'shareType' => $share->getShareType(),
1012
				'shareWith' => $share->getSharedWith(),
1013
				'uidOwner' => $share->getSharedBy(),
1014
				'permissions' => $share->getPermissions(),
1015
				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1016
			));
1017
		}
1018
1019
		return $share;
1020
	}
1021
1022
	/**
1023
	 * Accept a share.
1024
	 *
1025
	 * @param IShare $share
1026
	 * @param string $recipientId
1027
	 * @return IShare The share object
1028
	 * @throws \InvalidArgumentException
1029
	 * @since 9.0.0
1030
	 */
1031
	public function acceptShare(IShare $share, string $recipientId): IShare {
1032
		[$providerId, ] = $this->splitFullId($share->getFullId());
1033
		$provider = $this->factory->getProvider($providerId);
1034
1035
		if (!method_exists($provider, 'acceptShare')) {
1036
			// TODO FIX ME
1037
			throw new \InvalidArgumentException('Share provider does not support accepting');
1038
		}
1039
		$provider->acceptShare($share, $recipientId);
1040
		$event = new GenericEvent($share);
1041
		$this->eventDispatcher->dispatch('OCP\Share::postAcceptShare', $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

1041
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
1042
                          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...
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

1041
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postAcceptShare', $event);
Loading history...
1042
1043
		return $share;
1044
	}
1045
1046
	/**
1047
	 * Updates the password of the given share if it is not the same as the
1048
	 * password of the original share.
1049
	 *
1050
	 * @param \OCP\Share\IShare $share the share to update its password.
1051
	 * @param \OCP\Share\IShare $originalShare the original share to compare its
1052
	 *        password with.
1053
	 * @return boolean whether the password was updated or not.
1054
	 */
1055
	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
1056
		// Password updated.
1057
		if ($share->getPassword() !== $originalShare->getPassword()) {
1058
			//Verify the password
1059
			$this->verifyPassword($share->getPassword());
1060
1061
			// If a password is set. Hash it!
1062
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
1063
				$share->setPassword($this->hasher->hash($share->getPassword()));
1064
1065
				return true;
1066
			}
1067
		}
1068
1069
		return false;
1070
	}
1071
1072
	/**
1073
	 * Delete all the children of this share
1074
	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1075
	 *
1076
	 * @param \OCP\Share\IShare $share
1077
	 * @return \OCP\Share\IShare[] List of deleted shares
1078
	 */
1079
	protected function deleteChildren(\OCP\Share\IShare $share) {
1080
		$deletedShares = [];
1081
1082
		$provider = $this->factory->getProviderForType($share->getShareType());
1083
1084
		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

1084
		foreach ($provider->/** @scrutinizer ignore-call */ getChildren($share) as $child) {
Loading history...
1085
			$deletedChildren = $this->deleteChildren($child);
1086
			$deletedShares = array_merge($deletedShares, $deletedChildren);
1087
1088
			$provider->delete($child);
1089
			$deletedShares[] = $child;
1090
		}
1091
1092
		return $deletedShares;
1093
	}
1094
1095
	/**
1096
	 * Delete a share
1097
	 *
1098
	 * @param \OCP\Share\IShare $share
1099
	 * @throws ShareNotFound
1100
	 * @throws \InvalidArgumentException
1101
	 */
1102
	public function deleteShare(\OCP\Share\IShare $share) {
1103
1104
		try {
1105
			$share->getFullId();
1106
		} catch (\UnexpectedValueException $e) {
1107
			throw new \InvalidArgumentException('Share does not have a full id');
1108
		}
1109
1110
		$event = new GenericEvent($share);
1111
		$this->eventDispatcher->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

1111
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
1112
                          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

1111
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preUnshare', $event);
Loading history...
1112
1113
		// Get all children and delete them as well
1114
		$deletedShares = $this->deleteChildren($share);
1115
1116
		// Do the actual delete
1117
		$provider = $this->factory->getProviderForType($share->getShareType());
1118
		$provider->delete($share);
1119
1120
		// All the deleted shares caused by this delete
1121
		$deletedShares[] = $share;
1122
1123
		// Emit post hook
1124
		$event->setArgument('deletedShares', $deletedShares);
1125
		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
1126
	}
1127
1128
1129
	/**
1130
	 * Unshare a file as the recipient.
1131
	 * This can be different from a regular delete for example when one of
1132
	 * the users in a groups deletes that share. But the provider should
1133
	 * handle this.
1134
	 *
1135
	 * @param \OCP\Share\IShare $share
1136
	 * @param string $recipientId
1137
	 */
1138
	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
1139
		list($providerId, ) = $this->splitFullId($share->getFullId());
1140
		$provider = $this->factory->getProvider($providerId);
1141
1142
		$provider->deleteFromSelf($share, $recipientId);
1143
		$event = new GenericEvent($share);
1144
		$this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $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

1144
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
1145
                          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...
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

1144
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postUnshareFromSelf', $event);
Loading history...
1145
	}
1146
1147
	public function restoreShare(IShare $share, string $recipientId): IShare {
1148
		list($providerId, ) = $this->splitFullId($share->getFullId());
1149
		$provider = $this->factory->getProvider($providerId);
1150
1151
		return $provider->restore($share, $recipientId);
1152
	}
1153
1154
	/**
1155
	 * @inheritdoc
1156
	 */
1157
	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1158
		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

1158
		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...
1159
			throw new \InvalidArgumentException('Can’t change target of link share');
1160
		}
1161
1162
		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

1162
		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...
1163
			throw new \InvalidArgumentException('Invalid recipient');
1164
		}
1165
1166
		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

1166
		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...
1167
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1168
			if (is_null($sharedWith)) {
1169
				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1170
			}
1171
			$recipient = $this->userManager->get($recipientId);
1172
			if (!$sharedWith->inGroup($recipient)) {
1173
				throw new \InvalidArgumentException('Invalid recipient');
1174
			}
1175
		}
1176
1177
		list($providerId, ) = $this->splitFullId($share->getFullId());
1178
		$provider = $this->factory->getProvider($providerId);
1179
1180
		$provider->move($share, $recipientId);
1181
	}
1182
1183
	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1184
		$providers = $this->factory->getAllProviders();
1185
1186
		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1187
			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1188
			foreach ($newShares as $fid => $data) {
1189
				if (!isset($shares[$fid])) {
1190
					$shares[$fid] = [];
1191
				}
1192
1193
				$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

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

1332
		$share = $provider->getShareById(/** @scrutinizer ignore-type */ $id, $recipient);
Loading history...
1333
1334
		$this->checkExpireDate($share);
1335
1336
		return $share;
1337
	}
1338
1339
	/**
1340
	 * Get all the shares for a given path
1341
	 *
1342
	 * @param \OCP\Files\Node $path
1343
	 * @param int $page
1344
	 * @param int $perPage
1345
	 *
1346
	 * @return Share[]
1347
	 */
1348
	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

1348
	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

1348
	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

1348
	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...
1349
		return [];
1350
	}
1351
1352
	/**
1353
	 * Get the share by token possible with password
1354
	 *
1355
	 * @param string $token
1356
	 * @return Share
1357
	 *
1358
	 * @throws ShareNotFound
1359
	 */
1360
	public function getShareByToken($token) {
1361
		// tokens can't be valid local user names
1362
		if ($this->userManager->userExists($token)) {
1363
			throw new ShareNotFound();
1364
		}
1365
		$share = null;
1366
		try {
1367
			if($this->shareApiAllowLinks()) {
1368
				$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

1368
				$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...
1369
				$share = $provider->getShareByToken($token);
1370
			}
1371
		} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1372
		} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1373
		}
1374
1375
1376
		// If it is not a link share try to fetch a federated share by token
1377
		if ($share === null) {
1378
			try {
1379
				$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

1379
				$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...
1380
				$share = $provider->getShareByToken($token);
1381
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1382
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1383
			}
1384
		}
1385
1386
		// If it is not a link share try to fetch a mail share by token
1387
		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

1387
		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...
1388
			try {
1389
				$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

1389
				$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...
1390
				$share = $provider->getShareByToken($token);
1391
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1392
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1393
			}
1394
		}
1395
1396
		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

1396
		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...
1397
			try {
1398
				$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

1398
				$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...
1399
				$share = $provider->getShareByToken($token);
1400
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1401
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1402
			}
1403
		}
1404
1405
		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

1405
		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...
1406
			try {
1407
				$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

1407
				$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...
1408
				$share = $provider->getShareByToken($token);
1409
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1410
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1411
			}
1412
		}
1413
1414
		if ($share === null) {
1415
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1416
		}
1417
1418
		$this->checkExpireDate($share);
1419
1420
		/*
1421
		 * Reduce the permissions for link shares if public upload is not enabled
1422
		 */
1423
		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

1423
		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...
1424
			!$this->shareApiLinkAllowPublicUpload()) {
1425
			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1426
		}
1427
1428
		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...
1429
	}
1430
1431
	protected function checkExpireDate($share) {
1432
		if ($share->isExpired()) {
1433
			$this->deleteShare($share);
1434
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1435
		}
1436
1437
	}
1438
1439
	/**
1440
	 * Verify the password of a public share
1441
	 *
1442
	 * @param \OCP\Share\IShare $share
1443
	 * @param string $password
1444
	 * @return bool
1445
	 */
1446
	public function checkPassword(\OCP\Share\IShare $share, $password) {
1447
		$passwordProtected = $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

1447
		$passwordProtected = $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...
1448
			|| $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

1448
			|| $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...
1449
		if (!$passwordProtected) {
1450
			//TODO maybe exception?
1451
			return false;
1452
		}
1453
1454
		if ($password === null || $share->getPassword() === null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() === null is always false.
Loading history...
1455
			return false;
1456
		}
1457
1458
		$newHash = '';
1459
		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1460
			return false;
1461
		}
1462
1463
		if (!empty($newHash)) {
1464
			$share->setPassword($newHash);
1465
			$provider = $this->factory->getProviderForType($share->getShareType());
1466
			$provider->update($share);
1467
		}
1468
1469
		return true;
1470
	}
1471
1472
	/**
1473
	 * @inheritdoc
1474
	 */
1475
	public function userDeleted($uid) {
1476
		$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_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

1476
		$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

1476
		$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_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

1476
		$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_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

1476
		$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...
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

1476
		$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...
1477
1478
		foreach ($types as $type) {
1479
			try {
1480
				$provider = $this->factory->getProviderForType($type);
1481
			} catch (ProviderException $e) {
1482
				continue;
1483
			}
1484
			$provider->userDeleted($uid, $type);
1485
		}
1486
	}
1487
1488
	/**
1489
	 * @inheritdoc
1490
	 */
1491
	public function groupDeleted($gid) {
1492
		$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

1492
		$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...
1493
		$provider->groupDeleted($gid);
1494
	}
1495
1496
	/**
1497
	 * @inheritdoc
1498
	 */
1499
	public function userDeletedFromGroup($uid, $gid) {
1500
		$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

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