Passed
Push — master ( 768b01...652639 )
by Roeland
12:26 queued 14s
created

Manager::validateExpirationDateInternal()   C

Complexity

Conditions 12
Paths 73

Size

Total Lines 65
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 39
nc 73
nop 1
dl 0
loc 65
rs 6.9666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

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

Loading history...
220
			// We expect a valid user as sharedWith for user shares
221
			if (!$this->userManager->userExists($share->getSharedWith())) {
222
				throw new \InvalidArgumentException('SharedWith is not a valid user');
223
			}
224
		} 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
400
			$days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
401
			if ($days > $this->shareApiLinkDefaultExpireDays()) {
402
				$days = $this->shareApiLinkDefaultExpireDays();
403
			}
404
			$expirationDate->add(new \DateInterval('P'.$days.'D'));
405
		}
406
407
		// If we enforce the expiration date check that is does not exceed
408
		if ($this->shareApiInternalDefaultExpireDateEnforced()) {
409
			if ($expirationDate === null) {
410
				throw new \InvalidArgumentException('Expiration date is enforced');
411
			}
412
413
			$date = new \DateTime();
414
			$date->setTime(0, 0, 0);
415
			$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
416
			if ($date < $expirationDate) {
417
				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
418
				throw new GenericShareException($message, $message, 404);
419
			}
420
		}
421
422
		$accepted = true;
423
		$message = '';
424
		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
425
			'expirationDate' => &$expirationDate,
426
			'accepted' => &$accepted,
427
			'message' => &$message,
428
			'passwordSet' => $share->getPassword() !== null,
429
		]);
430
431
		if (!$accepted) {
0 ignored issues
show
introduced by
The condition $accepted is always true.
Loading history...
432
			throw new \Exception($message);
433
		}
434
435
		$share->setExpirationDate($expirationDate);
436
437
		return $share;
438
	}
439
440
	/**
441
	 * Validate if the expiration date fits the system settings
442
	 *
443
	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
444
	 * @return \OCP\Share\IShare The modified share object
445
	 * @throws GenericShareException
446
	 * @throws \InvalidArgumentException
447
	 * @throws \Exception
448
	 */
449
	protected function validateExpirationDate(\OCP\Share\IShare $share) {
450
		$expirationDate = $share->getExpirationDate();
451
452
		if ($expirationDate !== null) {
453
			//Make sure the expiration date is a date
454
			$expirationDate->setTime(0, 0, 0);
455
456
			$date = new \DateTime();
457
			$date->setTime(0, 0, 0);
458
			if ($date >= $expirationDate) {
459
				$message = $this->l->t('Expiration date is in the past');
460
				throw new GenericShareException($message, $message, 404);
461
			}
462
		}
463
464
		// If expiredate is empty set a default one if there is a default
465
		$fullId = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $fullId is dead and can be removed.
Loading history...
466
		try {
467
			$fullId = $share->getFullId();
468
		} catch (\UnexpectedValueException $e) {
469
			// This is a new share
470
		}
471
472
		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
0 ignored issues
show
introduced by
The condition $fullId === null is always false.
Loading history...
473
			$expirationDate = new \DateTime();
474
			$expirationDate->setTime(0,0,0);
475
476
			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
477
			if ($days > $this->shareApiLinkDefaultExpireDays()) {
478
				$days = $this->shareApiLinkDefaultExpireDays();
479
			}
480
			$expirationDate->add(new \DateInterval('P'.$days.'D'));
481
		}
482
483
		// If we enforce the expiration date check that is does not exceed
484
		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
485
			if ($expirationDate === null) {
486
				throw new \InvalidArgumentException('Expiration date is enforced');
487
			}
488
489
			$date = new \DateTime();
490
			$date->setTime(0, 0, 0);
491
			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
492
			if ($date < $expirationDate) {
493
				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
494
				throw new GenericShareException($message, $message, 404);
495
			}
496
		}
497
498
		$accepted = true;
499
		$message = '';
500
		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
501
			'expirationDate' => &$expirationDate,
502
			'accepted' => &$accepted,
503
			'message' => &$message,
504
			'passwordSet' => $share->getPassword() !== null,
505
		]);
506
507
		if (!$accepted) {
0 ignored issues
show
introduced by
The condition $accepted is always true.
Loading history...
508
			throw new \Exception($message);
509
		}
510
511
		$share->setExpirationDate($expirationDate);
512
513
		return $share;
514
	}
515
516
	/**
517
	 * Check for pre share requirements for user shares
518
	 *
519
	 * @param \OCP\Share\IShare $share
520
	 * @throws \Exception
521
	 */
522
	protected function userCreateChecks(\OCP\Share\IShare $share) {
523
		// Check if we can share with group members only
524
		if ($this->shareWithGroupMembersOnly()) {
525
			$sharedBy = $this->userManager->get($share->getSharedBy());
526
			$sharedWith = $this->userManager->get($share->getSharedWith());
527
			// Verify we can share with this user
528
			$groups = array_intersect(
529
					$this->groupManager->getUserGroupIds($sharedBy),
530
					$this->groupManager->getUserGroupIds($sharedWith)
531
			);
532
			if (empty($groups)) {
533
				throw new \Exception('Sharing is only allowed with group members');
534
			}
535
		}
536
537
		/*
538
		 * TODO: Could be costly, fix
539
		 *
540
		 * Also this is not what we want in the future.. then we want to squash identical shares.
541
		 */
542
		$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

542
		$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...
543
		$existingShares = $provider->getSharesByPath($share->getNode());
544
		foreach ($existingShares as $existingShare) {
545
			// Ignore if it is the same share
546
			try {
547
				if ($existingShare->getFullId() === $share->getFullId()) {
548
					continue;
549
				}
550
			} catch (\UnexpectedValueException $e) {
551
				//Shares are not identical
552
			}
553
554
			// Identical share already existst
555
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
556
				throw new \Exception('Path is already shared with this user');
557
			}
558
559
			// The share is already shared with this user via a group share
560
			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

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

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

731
		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...
732
			$this->userCreateChecks($share);
733
734
			//Verify the expiration date
735
			$share = $this->validateExpirationDateInternal($share);
736
		} 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

736
		} 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...
737
			$this->groupCreateChecks($share);
738
739
			//Verify the expiration date
740
			$share = $this->validateExpirationDateInternal($share);
741
		} 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

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

765
		} 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...
766
			$share->setToken(
767
				$this->secureRandom->generate(
768
					\OC\Share\Constants::TOKEN_LENGTH,
769
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
770
				)
771
			);
772
		}
773
774
		// Cannot share with the owner
775
		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

775
		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...
776
			$share->getSharedWith() === $share->getShareOwner()) {
777
			throw new \InvalidArgumentException('Can’t share with the share owner');
778
		}
779
780
		// Generate the target
781
		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
782
		$target = \OC\Files\Filesystem::normalizePath($target);
783
		$share->setTarget($target);
784
785
		// Pre share event
786
		$event = new GenericEvent($share);
787
		$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
0 ignored issues
show
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

787
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preShare', $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

787
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
788
                           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...
788
		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

788
		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...
789
			throw new \Exception($event->getArgument('error'));
790
		}
791
792
		$oldShare = $share;
793
		$provider = $this->factory->getProviderForType($share->getShareType());
794
		$share = $provider->create($share);
795
		//reuse the node we already have
796
		$share->setNode($oldShare->getNode());
797
798
		// Reset the target if it is null for the new share
799
		if ($share->getTarget() === '') {
800
			$share->setTarget($target);
801
		}
802
803
		// Post share event
804
		$event = new GenericEvent($share);
805
		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
806
807
		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
808
809
		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

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

946
			$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...
947
			throw new \InvalidArgumentException('Can only update recipient on user shares');
948
		}
949
950
		// Cannot share with the owner
951
		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

951
		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...
952
			$share->getSharedWith() === $share->getShareOwner()) {
953
			throw new \InvalidArgumentException('Can’t share with the share owner');
954
		}
955
956
		$this->generalCreateChecks($share);
957
958
		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

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

966
		} 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...
967
			$this->groupCreateChecks($share);
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_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

974
		} 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...
975
			$this->linkCreateChecks($share);
976
977
			$this->updateSharePasswordIfNeeded($share, $originalShare);
978
979
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
980
				//Verify the expiration date
981
				$this->validateExpirationDate($share);
982
				$expirationDateUpdated = true;
983
			}
984
		} 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

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

1005
		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...
1006
			$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

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

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

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

1112
		foreach ($provider->/** @scrutinizer ignore-call */ getChildren($share) as $child) {
Loading history...
1113
			$deletedChildren = $this->deleteChildren($child);
1114
			$deletedShares = array_merge($deletedShares, $deletedChildren);
1115
1116
			$provider->delete($child);
1117
			$deletedShares[] = $child;
1118
		}
1119
1120
		return $deletedShares;
1121
	}
1122
1123
	/**
1124
	 * Delete a share
1125
	 *
1126
	 * @param \OCP\Share\IShare $share
1127
	 * @throws ShareNotFound
1128
	 * @throws \InvalidArgumentException
1129
	 */
1130
	public function deleteShare(\OCP\Share\IShare $share) {
1131
		try {
1132
			$share->getFullId();
1133
		} catch (\UnexpectedValueException $e) {
1134
			throw new \InvalidArgumentException('Share does not have a full id');
1135
		}
1136
1137
		$event = new GenericEvent($share);
1138
		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
0 ignored issues
show
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

1138
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preUnshare', $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

1138
		$this->legacyDispatcher->/** @scrutinizer ignore-call */ 
1139
                           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...
1139
1140
		// Get all children and delete them as well
1141
		$deletedShares = $this->deleteChildren($share);
1142
1143
		// Do the actual delete
1144
		$provider = $this->factory->getProviderForType($share->getShareType());
1145
		$provider->delete($share);
1146
1147
		// All the deleted shares caused by this delete
1148
		$deletedShares[] = $share;
1149
1150
		// Emit post hook
1151
		$event->setArgument('deletedShares', $deletedShares);
1152
		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1153
	}
1154
1155
1156
	/**
1157
	 * Unshare a file as the recipient.
1158
	 * This can be different from a regular delete for example when one of
1159
	 * the users in a groups deletes that share. But the provider should
1160
	 * handle this.
1161
	 *
1162
	 * @param \OCP\Share\IShare $share
1163
	 * @param string $recipientId
1164
	 */
1165
	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
1166
		list($providerId, ) = $this->splitFullId($share->getFullId());
1167
		$provider = $this->factory->getProvider($providerId);
1168
1169
		$provider->deleteFromSelf($share, $recipientId);
1170
		$event = new GenericEvent($share);
1171
		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

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

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

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

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

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

1171
		$this->legacyDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postUnshareFromSelf', $event);
Loading history...
1172
	}
1173
1174
	public function restoreShare(IShare $share, string $recipientId): IShare {
1175
		list($providerId, ) = $this->splitFullId($share->getFullId());
1176
		$provider = $this->factory->getProvider($providerId);
1177
1178
		return $provider->restore($share, $recipientId);
1179
	}
1180
1181
	/**
1182
	 * @inheritdoc
1183
	 */
1184
	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1185
		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

1185
		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...
1186
			throw new \InvalidArgumentException('Can’t change target of link share');
1187
		}
1188
1189
		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

1189
		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...
1190
			throw new \InvalidArgumentException('Invalid recipient');
1191
		}
1192
1193
		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

1193
		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...
1194
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1195
			if (is_null($sharedWith)) {
1196
				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1197
			}
1198
			$recipient = $this->userManager->get($recipientId);
1199
			if (!$sharedWith->inGroup($recipient)) {
1200
				throw new \InvalidArgumentException('Invalid recipient');
1201
			}
1202
		}
1203
1204
		list($providerId, ) = $this->splitFullId($share->getFullId());
1205
		$provider = $this->factory->getProvider($providerId);
1206
1207
		$provider->move($share, $recipientId);
1208
	}
1209
1210
	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1211
		$providers = $this->factory->getAllProviders();
1212
1213
		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1214
			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1215
			foreach ($newShares as $fid => $data) {
1216
				if (!isset($shares[$fid])) {
1217
					$shares[$fid] = [];
1218
				}
1219
1220
				$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

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

1358
		$share = $provider->getShareById(/** @scrutinizer ignore-type */ $id, $recipient);
Loading history...
1359
1360
		$this->checkExpireDate($share);
1361
1362
		return $share;
1363
	}
1364
1365
	/**
1366
	 * Get all the shares for a given path
1367
	 *
1368
	 * @param \OCP\Files\Node $path
1369
	 * @param int $page
1370
	 * @param int $perPage
1371
	 *
1372
	 * @return Share[]
1373
	 */
1374
	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

1374
	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

1374
	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

1374
	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...
1375
		return [];
1376
	}
1377
1378
	/**
1379
	 * Get the share by token possible with password
1380
	 *
1381
	 * @param string $token
1382
	 * @return Share
1383
	 *
1384
	 * @throws ShareNotFound
1385
	 */
1386
	public function getShareByToken($token) {
1387
		// tokens can't be valid local user names
1388
		if ($this->userManager->userExists($token)) {
1389
			throw new ShareNotFound();
1390
		}
1391
		$share = null;
1392
		try {
1393
			if ($this->shareApiAllowLinks()) {
1394
				$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

1394
				$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...
1395
				$share = $provider->getShareByToken($token);
1396
			}
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 federated share by token
1403
		if ($share === null) {
1404
			try {
1405
				$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

1405
				$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...
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 it is not a link share try to fetch a mail share by token
1413
		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

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

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

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

1424
				$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...
1425
				$share = $provider->getShareByToken($token);
1426
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1427
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1428
			}
1429
		}
1430
1431
		if ($share === null && $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

1431
		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...
1432
			try {
1433
				$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

1433
				$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...
1434
				$share = $provider->getShareByToken($token);
1435
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1436
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1437
			}
1438
		}
1439
1440
		if ($share === null) {
1441
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1442
		}
1443
1444
		$this->checkExpireDate($share);
1445
1446
		/*
1447
		 * Reduce the permissions for link shares if public upload is not enabled
1448
		 */
1449
		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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1502
		$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...
1503
1504
		foreach ($types as $type) {
1505
			try {
1506
				$provider = $this->factory->getProviderForType($type);
1507
			} catch (ProviderException $e) {
1508
				continue;
1509
			}
1510
			$provider->userDeleted($uid, $type);
1511
		}
1512
	}
1513
1514
	/**
1515
	 * @inheritdoc
1516
	 */
1517
	public function groupDeleted($gid) {
1518
		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

1518
		$provider = $this->factory->getProviderForType(/** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_GROUP);

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

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

Loading history...
1519
		$provider->groupDeleted($gid);
1520
	}
1521
1522
	/**
1523
	 * @inheritdoc
1524
	 */
1525
	public function userDeletedFromGroup($uid, $gid) {
1526
		$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

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