Passed
Push — master ( cde6d7...0bd738 )
by Joas
12:02 queued 12s
created

Manager   F

Complexity

Total Complexity 287

Size/Duplication

Total Lines 1770
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 744
dl 0
loc 1770
rs 1.856
c 2
b 0
f 0
wmc 287

55 Methods

Rating   Name   Duplication   Size   Complexity  
A verifyPassword() 0 15 4
A splitFullId() 0 2 1
A __construct() 0 36 1
B validateExpirationDateInternal() 0 60 11
A deleteFromSelf() 0 7 1
A restoreShare() 0 5 1
B moveShare() 0 24 7
A getSharesInFolder() 0 14 3
C userCreateChecks() 0 45 12
A pathCreateChecks() 0 7 4
A canShare() 0 7 3
B groupCreateChecks() 0 33 10
A setLinkParent() 0 8 3
A linkCreateChecks() 0 15 5
B validateExpirationDate() 0 60 11
A deleteChildren() 0 14 2
A getSharesByPath() 0 2 1
A shareApiEnabled() 0 2 1
F generalCreateChecks() 0 142 39
A shareApiAllowLinks() 0 2 1
A getShareById() 0 18 3
A allowEnumeration() 0 2 1
C getSharesBy() 0 68 13
A userDeletedFromGroup() 0 3 1
F getAccessList() 0 83 17
A outgoingServer2ServerSharesAllowed() 0 2 1
A newShare() 0 2 1
B sharingDisabledForUser() 0 32 7
A shareApiLinkEnforcePassword() 0 2 1
A shareApiLinkAllowPublicUpload() 0 2 1
A userDeleted() 0 10 3
F updateShare() 0 120 29
A shareProviderExists() 0 8 2
F getShareByToken() 0 69 23
A getAllShares() 0 5 2
B checkPassword() 0 25 8
A groupDeleted() 0 3 1
A deleteShare() 0 23 2
A getDeletedSharedWith() 0 14 1
A shareWithGroupMembersOnly() 0 2 1
F createShare() 0 136 19
A getSharedWith() 0 19 4
A allowGroupSharing() 0 2 1
A checkExpireDate() 0 4 2
A shareApiLinkDefaultExpireDays() 0 2 1
A updateSharePasswordIfNeeded() 0 15 3
A shareApiLinkDefaultExpireDateEnforced() 0 3 2
A shareApiInternalDefaultExpireDate() 0 2 1
A shareApiInternalDefaultExpireDays() 0 2 1
A outgoingServer2ServerGroupSharesAllowed() 0 2 1
A limitEnumerationToGroups() 0 3 2
A shareApiInternalDefaultExpireDateEnforced() 0 3 2
B sendMailNotification() 0 65 6
A acceptShare() 0 13 2
A shareApiLinkDefaultExpireDate() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like Manager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Manager, and based on these observations, apply Extract Interface, too.

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

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

Loading history...
220
			// We expect a valid user as sharedWith for user shares
221
			if (!$this->userManager->userExists($share->getSharedWith())) {
222
				throw new \InvalidArgumentException('SharedWith is not a valid user');
223
			}
224
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

224
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_GROUP) {

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

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

Loading history...
225
			// We expect a valid group as sharedWith for group shares
226
			if (!$this->groupManager->groupExists($share->getSharedWith())) {
227
				throw new \InvalidArgumentException('SharedWith is not a valid group');
228
			}
229
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

229
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK) {

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

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

Loading history...
230
			if ($share->getSharedWith() !== null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() !== null is always true.
Loading history...
231
				throw new \InvalidArgumentException('SharedWith should be empty');
232
			}
233
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE has been deprecated: 17.0.0 - use IShare::TYPE_REMOTE instead ( Ignorable by Annotation )

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

233
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_REMOTE) {

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

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

Loading history...
234
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
235
				throw new \InvalidArgumentException('SharedWith should not be empty');
236
			}
237
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_REMOTE_GROUP has been deprecated: 17.0.0 - use IShare::REMOTE_GROUP instead ( Ignorable by Annotation )

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

237
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {

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

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

Loading history...
238
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
239
				throw new \InvalidArgumentException('SharedWith should not be empty');
240
			}
241
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

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

241
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_EMAIL) {

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

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

Loading history...
242
			if ($share->getSharedWith() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedWith() === null is always false.
Loading history...
243
				throw new \InvalidArgumentException('SharedWith should not be empty');
244
			}
245
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

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

245
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_CIRCLE) {

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

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

Loading history...
246
			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
0 ignored issues
show
Bug introduced by
The type OCA\Circles\Api\v1\Circles was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
247
			if ($circle === null) {
248
				throw new \InvalidArgumentException('SharedWith is not a valid circle');
249
			}
250
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_ROOM) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

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

250
		} elseif ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_ROOM) {

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

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

Loading history...
251
		} else {
252
			// We can't handle other types yet
253
			throw new \InvalidArgumentException('unknown share type');
254
		}
255
256
		// Verify the initiator of the share is set
257
		if ($share->getSharedBy() === null) {
0 ignored issues
show
introduced by
The condition $share->getSharedBy() === null is always false.
Loading history...
258
			throw new \InvalidArgumentException('SharedBy should be set');
259
		}
260
261
		// Cannot share with yourself
262
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

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

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

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

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

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

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

312
			$incomingShares = $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_USER, $userMountPoint, -1, 0);

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

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

Loading history...
313
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_GROUP, $userMountPoint, -1, 0));
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

313
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_GROUP, $userMountPoint, -1, 0));

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

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

Loading history...
314
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_CIRCLE, $userMountPoint, -1, 0));
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_CIRCLE has been deprecated: 17.0.0 - use IShare::TYPE_CIRCLE instead ( Ignorable by Annotation )

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

314
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_CIRCLE, $userMountPoint, -1, 0));

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

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

Loading history...
315
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_ROOM, $userMountPoint, -1, 0));
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_ROOM has been deprecated: 17.0.0 - use IShare::TYPE_ROOM instead ( Ignorable by Annotation )

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

315
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), /** @scrutinizer ignore-deprecated */ Share::SHARE_TYPE_ROOM, $userMountPoint, -1, 0));

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

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

Loading history...
316
317
			/** @var \OCP\Share\IShare[] $incomingShares */
318
			if (!empty($incomingShares)) {
319
				foreach ($incomingShares as $incomingShare) {
320
					$permissions |= $incomingShare->getPermissions();
321
				}
322
			}
323
		} else {
324
			/*
325
			 * Quick fix for #23536
326
			 * Non moveable mount points do not have update and delete permissions
327
			 * while we 'most likely' do have that on the storage.
328
			 */
329
			$permissions = $share->getNode()->getPermissions();
330
			if (!($mount instanceof MoveableMount)) {
331
				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
332
			}
333
		}
334
335
		// Check that we do not share with more permissions than we have
336
		if ($share->getPermissions() & ~$permissions) {
337
			$path = $userFolder->getRelativePath($share->getNode()->getPath());
338
			$message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
339
			throw new GenericShareException($message_t, $message_t, 404);
340
		}
341
342
343
		// Check that read permissions are always set
344
		// Link shares are allowed to have no read permissions to allow upload to hidden folders
345
		$noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

345
		$noReadPermissionRequired = $share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK

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

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

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

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

346
			|| $share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_EMAIL;

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

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

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

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

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

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

721
		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...
722
			$this->userCreateChecks($share);
723
724
			//Verify the expiration date
725
			$share = $this->validateExpirationDateInternal($share);
726
		} elseif ($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

726
		} elseif ($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...
727
			$this->groupCreateChecks($share);
728
729
			//Verify the expiration date
730
			$share = $this->validateExpirationDateInternal($share);
731
		} elseif ($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

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

755
		} elseif ($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...
756
			$share->setToken(
757
				$this->secureRandom->generate(
758
					\OC\Share\Constants::TOKEN_LENGTH,
759
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
760
				)
761
			);
762
		}
763
764
		// Cannot share with the owner
765
		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

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

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

777
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
778
                           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

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

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

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

936
			$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...
937
			throw new \InvalidArgumentException('Can only update recipient on user shares');
938
		}
939
940
		// Cannot share with the owner
941
		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

941
		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...
942
			$share->getSharedWith() === $share->getShareOwner()) {
943
			throw new \InvalidArgumentException('Can’t share with the share owner');
944
		}
945
946
		$this->generalCreateChecks($share);
947
948
		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

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

956
		} elseif ($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...
957
			$this->groupCreateChecks($share);
958
959
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
960
				//Verify the expiration date
961
				$this->validateExpirationDate($share);
962
				$expirationDateUpdated = true;
963
			}
964
		} elseif ($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

964
		} elseif ($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...
965
			$this->linkCreateChecks($share);
966
967
			$this->updateSharePasswordIfNeeded($share, $originalShare);
968
969
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
970
				//Verify the expiration date
971
				$this->validateExpirationDate($share);
972
				$expirationDateUpdated = true;
973
			}
974
		} elseif ($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

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

995
		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...
996
			$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

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

1059
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
1060
                           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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1162
	}
1163
1164
	public function restoreShare(IShare $share, string $recipientId): IShare {
1165
		list($providerId, ) = $this->splitFullId($share->getFullId());
1166
		$provider = $this->factory->getProvider($providerId);
1167
1168
		return $provider->restore($share, $recipientId);
1169
	}
1170
1171
	/**
1172
	 * @inheritdoc
1173
	 */
1174
	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1175
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

1175
		if ($share->getShareType() === /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK) {

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

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

Loading history...
1176
			throw new \InvalidArgumentException('Can’t change target of link share');
1177
		}
1178
1179
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
1180
			throw new \InvalidArgumentException('Invalid recipient');
1181
		}
1182
1183
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

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

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

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

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

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

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

1348
		$share = $provider->getShareById(/** @scrutinizer ignore-type */ $id, $recipient);
Loading history...
1349
1350
		$this->checkExpireDate($share);
1351
1352
		return $share;
1353
	}
1354
1355
	/**
1356
	 * Get all the shares for a given path
1357
	 *
1358
	 * @param \OCP\Files\Node $path
1359
	 * @param int $page
1360
	 * @param int $perPage
1361
	 *
1362
	 * @return Share[]
1363
	 */
1364
	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
0 ignored issues
show
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

1364
	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...
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

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

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

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

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

1403
		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...
1404
			try {
1405
				$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

1405
				$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...
1406
				$share = $provider->getShareByToken($token);
1407
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1408
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1409
			}
1410
		}
1411
1412
		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

1412
		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...
1413
			try {
1414
				$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

1414
				$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...
1415
				$share = $provider->getShareByToken($token);
1416
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1417
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1418
			}
1419
		}
1420
1421
		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

1421
		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...
1422
			try {
1423
				$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

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

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

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

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

1492
		$types = [/** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];

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

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

Loading history...
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_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

1492
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];

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

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

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

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

1492
		$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...
1493
1494
		foreach ($types as $type) {
1495
			try {
1496
				$provider = $this->factory->getProviderForType($type);
1497
			} catch (ProviderException $e) {
1498
				continue;
1499
			}
1500
			$provider->userDeleted($uid, $type);
1501
		}
1502
	}
1503
1504
	/**
1505
	 * @inheritdoc
1506
	 */
1507
	public function groupDeleted($gid) {
1508
		$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

1508
		$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...
1509
		$provider->groupDeleted($gid);
1510
	}
1511
1512
	/**
1513
	 * @inheritdoc
1514
	 */
1515
	public function userDeletedFromGroup($uid, $gid) {
1516
		$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

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