Passed
Push — master ( ef6806...fd475d )
by Roeland
09:13 queued 10s
created

Manager::newShare()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

195
			$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\PasswordPolicy::validate', $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

195
			$this->eventDispatcher->/** @scrutinizer ignore-call */ 
196
                           dispatch('OCP\PasswordPolicy::validate', $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...
196
		} catch (HintException $e) {
197
			throw new \Exception($e->getHint());
198
		}
199
	}
200
201
	/**
202
	 * Check for generic requirements before creating a share
203
	 *
204
	 * @param \OCP\Share\IShare $share
205
	 * @throws \InvalidArgumentException
206
	 * @throws GenericShareException
207
	 *
208
	 * @suppress PhanUndeclaredClassMethod
209
	 */
210
	protected function generalCreateChecks(\OCP\Share\IShare $share) {
211
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

filter:
    dependency_paths: ["lib/*"]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
305
			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), Share::SHARE_TYPE_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

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

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

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

451
		$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...
452
		$existingShares = $provider->getSharesByPath($share->getNode());
453
		foreach($existingShares as $existingShare) {
454
			// Ignore if it is the same share
455
			try {
456
				if ($existingShare->getFullId() === $share->getFullId()) {
457
					continue;
458
				}
459
			} catch (\UnexpectedValueException $e) {
460
				//Shares are not identical
461
			}
462
463
			// Identical share already existst
464
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
465
				throw new \Exception('Path is already shared with this user');
466
			}
467
468
			// The share is already shared with this user via a group share
469
			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

469
			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...
470
				$group = $this->groupManager->get($existingShare->getSharedWith());
471
				if (!is_null($group)) {
472
					$user = $this->userManager->get($share->getSharedWith());
473
474
					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
475
						throw new \Exception('Path is already shared with this user');
476
					}
477
				}
478
			}
479
		}
480
	}
481
482
	/**
483
	 * Check for pre share requirements for group shares
484
	 *
485
	 * @param \OCP\Share\IShare $share
486
	 * @throws \Exception
487
	 */
488
	protected function groupCreateChecks(\OCP\Share\IShare $share) {
489
		// Verify group shares are allowed
490
		if (!$this->allowGroupSharing()) {
491
			throw new \Exception('Group sharing is now allowed');
492
		}
493
494
		// Verify if the user can share with this group
495
		if ($this->shareWithGroupMembersOnly()) {
496
			$sharedBy = $this->userManager->get($share->getSharedBy());
497
			$sharedWith = $this->groupManager->get($share->getSharedWith());
498
			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
499
				throw new \Exception('Sharing is only allowed within your own groups');
500
			}
501
		}
502
503
		/*
504
		 * TODO: Could be costly, fix
505
		 *
506
		 * Also this is not what we want in the future.. then we want to squash identical shares.
507
		 */
508
		$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

508
		$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...
509
		$existingShares = $provider->getSharesByPath($share->getNode());
510
		foreach($existingShares as $existingShare) {
511
			try {
512
				if ($existingShare->getFullId() === $share->getFullId()) {
513
					continue;
514
				}
515
			} catch (\UnexpectedValueException $e) {
516
				//It is a new share so just continue
517
			}
518
519
			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
520
				throw new \Exception('Path is already shared with this group');
521
			}
522
		}
523
	}
524
525
	/**
526
	 * Check for pre share requirements for link shares
527
	 *
528
	 * @param \OCP\Share\IShare $share
529
	 * @throws \Exception
530
	 */
531
	protected function linkCreateChecks(\OCP\Share\IShare $share) {
532
		// Are link shares allowed?
533
		if (!$this->shareApiAllowLinks()) {
534
			throw new \Exception('Link sharing is not allowed');
535
		}
536
537
		// Link shares by definition can't have share permissions
538
		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
539
			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
540
		}
541
542
		// Check if public upload is allowed
543
		if (!$this->shareApiLinkAllowPublicUpload() &&
544
			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
545
			throw new \InvalidArgumentException('Public upload is not allowed');
546
		}
547
	}
548
549
	/**
550
	 * To make sure we don't get invisible link shares we set the parent
551
	 * of a link if it is a reshare. This is a quick word around
552
	 * until we can properly display multiple link shares in the UI
553
	 *
554
	 * See: https://github.com/owncloud/core/issues/22295
555
	 *
556
	 * FIXME: Remove once multiple link shares can be properly displayed
557
	 *
558
	 * @param \OCP\Share\IShare $share
559
	 */
560
	protected function setLinkParent(\OCP\Share\IShare $share) {
561
562
		// No sense in checking if the method is not there.
563
		if (method_exists($share, 'setParent')) {
564
			$storage = $share->getNode()->getStorage();
565
			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
566
				/** @var \OCA\Files_Sharing\SharedStorage $storage */
567
				$share->setParent($storage->getShareId());
568
			}
569
		}
570
	}
571
572
	/**
573
	 * @param File|Folder $path
574
	 */
575
	protected function pathCreateChecks($path) {
576
		// Make sure that we do not share a path that contains a shared mountpoint
577
		if ($path instanceof \OCP\Files\Folder) {
578
			$mounts = $this->mountManager->findIn($path->getPath());
579
			foreach($mounts as $mount) {
580
				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
581
					throw new \InvalidArgumentException('Path contains files shared with you');
582
				}
583
			}
584
		}
585
	}
586
587
	/**
588
	 * Check if the user that is sharing can actually share
589
	 *
590
	 * @param \OCP\Share\IShare $share
591
	 * @throws \Exception
592
	 */
593
	protected function canShare(\OCP\Share\IShare $share) {
594
		if (!$this->shareApiEnabled()) {
595
			throw new \Exception('Sharing is disabled');
596
		}
597
598
		if ($this->sharingDisabledForUser($share->getSharedBy())) {
599
			throw new \Exception('Sharing is disabled for you');
600
		}
601
	}
602
603
	/**
604
	 * Share a path
605
	 *
606
	 * @param \OCP\Share\IShare $share
607
	 * @return Share The share object
608
	 * @throws \Exception
609
	 *
610
	 * TODO: handle link share permissions or check them
611
	 */
612
	public function createShare(\OCP\Share\IShare $share) {
613
		$this->canShare($share);
614
615
		$this->generalCreateChecks($share);
616
617
		// Verify if there are any issues with the path
618
		$this->pathCreateChecks($share->getNode());
619
620
		/*
621
		 * On creation of a share the owner is always the owner of the path
622
		 * Except for mounted federated shares.
623
		 */
624
		$storage = $share->getNode()->getStorage();
625
		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
626
			$parent = $share->getNode()->getParent();
627
			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
628
				$parent = $parent->getParent();
629
			}
630
			$share->setShareOwner($parent->getOwner()->getUID());
631
		} else {
632
			$share->setShareOwner($share->getNode()->getOwner()->getUID());
633
		}
634
635
		//Verify share type
636
		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

636
		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...
637
			$this->userCreateChecks($share);
638
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
639
			$this->groupCreateChecks($share);
640
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
641
			$this->linkCreateChecks($share);
642
			$this->setLinkParent($share);
643
644
			/*
645
			 * For now ignore a set token.
646
			 */
647
			$share->setToken(
648
				$this->secureRandom->generate(
649
					\OC\Share\Constants::TOKEN_LENGTH,
650
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
651
				)
652
			);
653
654
			//Verify the expiration date
655
			$this->validateExpirationDate($share);
656
657
			//Verify the password
658
			$this->verifyPassword($share->getPassword());
659
660
			// If a password is set. Hash it!
661
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
662
				$share->setPassword($this->hasher->hash($share->getPassword()));
663
			}
664
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
665
			$share->setToken(
666
				$this->secureRandom->generate(
667
					\OC\Share\Constants::TOKEN_LENGTH,
668
					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
669
				)
670
			);
671
		}
672
673
		// Cannot share with the owner
674
		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

674
		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...
675
			$share->getSharedWith() === $share->getShareOwner()) {
676
			throw new \InvalidArgumentException('Can’t share with the share owner');
677
		}
678
679
		// Generate the target
680
		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
681
		$target = \OC\Files\Filesystem::normalizePath($target);
682
		$share->setTarget($target);
683
684
		// Pre share event
685
		$event = new GenericEvent($share);
686
		$this->eventDispatcher->dispatch('OCP\Share::preShare', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

686
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
687
                          dispatch('OCP\Share::preShare', $event);

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

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

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

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

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

687
		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...
688
			throw new \Exception($event->getArgument('error'));
689
		}
690
691
		$oldShare = $share;
692
		$provider = $this->factory->getProviderForType($share->getShareType());
693
		$share = $provider->create($share);
694
		//reuse the node we already have
695
		$share->setNode($oldShare->getNode());
696
697
		// Post share event
698
		$event = new GenericEvent($share);
699
		$this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
700
701
		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

701
		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...
702
			$mailSend = $share->getMailSend();
703
			if($mailSend === true) {
704
				$user = $this->userManager->get($share->getSharedWith());
705
				if ($user !== null) {
706
					$emailAddress = $user->getEMailAddress();
707
					if ($emailAddress !== null && $emailAddress !== '') {
708
						$userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
709
						$l = $this->l10nFactory->get('lib', $userLang);
710
						$this->sendMailNotification(
711
							$l,
712
							$share->getNode()->getName(),
713
							$this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]),
714
							$share->getSharedBy(),
715
							$emailAddress,
716
							$share->getExpirationDate()
717
						);
718
						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
719
					} else {
720
						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
721
					}
722
				} else {
723
					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
724
				}
725
			} else {
726
				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
727
			}
728
		}
729
730
		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...
731
	}
732
733
	/**
734
	 * Send mail notifications
735
	 *
736
	 * This method will catch and log mail transmission errors
737
	 *
738
	 * @param IL10N $l Language of the recipient
739
	 * @param string $filename file/folder name
740
	 * @param string $link link to the file/folder
741
	 * @param string $initiator user ID of share sender
742
	 * @param string $shareWith email address of share receiver
743
	 * @param \DateTime|null $expiration
744
	 */
745
	protected function sendMailNotification(IL10N $l,
746
											$filename,
747
											$link,
748
											$initiator,
749
											$shareWith,
750
											\DateTime $expiration = null) {
751
		$initiatorUser = $this->userManager->get($initiator);
752
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
753
754
		$message = $this->mailer->createMessage();
755
756
		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
757
			'filename' => $filename,
758
			'link' => $link,
759
			'initiator' => $initiatorDisplayName,
760
			'expiration' => $expiration,
761
			'shareWith' => $shareWith,
762
		]);
763
764
		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename)));
765
		$emailTemplate->addHeader();
766
		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
767
		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
768
769
		$emailTemplate->addBodyText(
770
			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
771
			$text
772
		);
773
		$emailTemplate->addBodyButton(
774
			$l->t('Open »%s«', [$filename]),
775
			$link
776
		);
777
778
		$message->setTo([$shareWith]);
779
780
		// The "From" contains the sharers name
781
		$instanceName = $this->defaults->getName();
782
		$senderName = $l->t(
783
			'%1$s via %2$s',
784
			[
785
				$initiatorDisplayName,
786
				$instanceName
787
			]
788
		);
789
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
790
791
		// The "Reply-To" is set to the sharer if an mail address is configured
792
		// also the default footer contains a "Do not reply" which needs to be adjusted.
793
		$initiatorEmail = $initiatorUser->getEMailAddress();
794
		if($initiatorEmail !== null) {
795
			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
796
			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
797
		} else {
798
			$emailTemplate->addFooter();
799
		}
800
801
		$message->useTemplate($emailTemplate);
802
		try {
803
			$failedRecipients = $this->mailer->send($message);
804
			if(!empty($failedRecipients)) {
805
				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
806
				return;
807
			}
808
		} catch (\Exception $e) {
809
			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
810
		}
811
	}
812
813
	/**
814
	 * Update a share
815
	 *
816
	 * @param \OCP\Share\IShare $share
817
	 * @return \OCP\Share\IShare The share object
818
	 * @throws \InvalidArgumentException
819
	 */
820
	public function updateShare(\OCP\Share\IShare $share) {
821
		$expirationDateUpdated = false;
822
823
		$this->canShare($share);
824
825
		try {
826
			$originalShare = $this->getShareById($share->getFullId());
827
		} catch (\UnexpectedValueException $e) {
828
			throw new \InvalidArgumentException('Share does not have a full id');
829
		}
830
831
		// We can't change the share type!
832
		if ($share->getShareType() !== $originalShare->getShareType()) {
833
			throw new \InvalidArgumentException('Can’t change share type');
834
		}
835
836
		// We can only change the recipient on user shares
837
		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
838
		    $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

838
		    $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...
839
			throw new \InvalidArgumentException('Can only update recipient on user shares');
840
		}
841
842
		// Cannot share with the owner
843
		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

843
		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...
844
			$share->getSharedWith() === $share->getShareOwner()) {
845
			throw new \InvalidArgumentException('Can’t share with the share owner');
846
		}
847
848
		$this->generalCreateChecks($share);
849
850
		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

850
		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...
851
			$this->userCreateChecks($share);
852
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_GROUP has been deprecated: 17.0.0 - use IShare::TYPE_GROUP instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
853
			$this->groupCreateChecks($share);
854
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
855
			$this->linkCreateChecks($share);
856
857
			$this->updateSharePasswordIfNeeded($share, $originalShare);
858
859
			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
860
				//Verify the expiration date
861
				$this->validateExpirationDate($share);
862
				$expirationDateUpdated = true;
863
			}
864
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_EMAIL has been deprecated: 17.0.0 - use IShare::TYPE_EMAIL instead ( Ignorable by Annotation )

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

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

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

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

Loading history...
865
			// The new password is not set again if it is the same as the old
866
			// one, unless when switching from sending by Talk to sending by
867
			// mail.
868
			$plainTextPassword = $share->getPassword();
869
			if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
870
					!($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
871
				$plainTextPassword = null;
872
			}
873
			if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
874
				// If the same password was already sent by mail the recipient
875
				// would already have access to the share without having to call
876
				// the sharer to verify her identity
877
				throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
878
			}
879
		}
880
881
		$this->pathCreateChecks($share->getNode());
882
883
		// Now update the share!
884
		$provider = $this->factory->getProviderForType($share->getShareType());
885
		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

885
		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...
886
			$share = $provider->update($share, $plainTextPassword);
0 ignored issues
show
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

886
			/** @scrutinizer ignore-call */ 
887
   $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...
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...
887
		} else {
888
			$share = $provider->update($share);
889
		}
890
891
		if ($expirationDateUpdated === true) {
892
			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
893
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
894
				'itemSource' => $share->getNode()->getId(),
895
				'date' => $share->getExpirationDate(),
896
				'uidOwner' => $share->getSharedBy(),
897
			]);
898
		}
899
900
		if ($share->getPassword() !== $originalShare->getPassword()) {
901
			\OC_Hook::emit(Share::class, 'post_update_password', [
902
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
903
				'itemSource' => $share->getNode()->getId(),
904
				'uidOwner' => $share->getSharedBy(),
905
				'token' => $share->getToken(),
906
				'disabled' => is_null($share->getPassword()),
907
			]);
908
		}
909
910
		if ($share->getPermissions() !== $originalShare->getPermissions()) {
911
			if ($this->userManager->userExists($share->getShareOwner())) {
912
				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
913
			} else {
914
				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
915
			}
916
			\OC_Hook::emit(Share::class, 'post_update_permissions', array(
917
				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
918
				'itemSource' => $share->getNode()->getId(),
919
				'shareType' => $share->getShareType(),
920
				'shareWith' => $share->getSharedWith(),
921
				'uidOwner' => $share->getSharedBy(),
922
				'permissions' => $share->getPermissions(),
923
				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
924
			));
925
		}
926
927
		return $share;
928
	}
929
930
	/**
931
	 * Updates the password of the given share if it is not the same as the
932
	 * password of the original share.
933
	 *
934
	 * @param \OCP\Share\IShare $share the share to update its password.
935
	 * @param \OCP\Share\IShare $originalShare the original share to compare its
936
	 *        password with.
937
	 * @return boolean whether the password was updated or not.
938
	 */
939
	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
940
		// Password updated.
941
		if ($share->getPassword() !== $originalShare->getPassword()) {
942
			//Verify the password
943
			$this->verifyPassword($share->getPassword());
944
945
			// If a password is set. Hash it!
946
			if ($share->getPassword() !== null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() !== null is always true.
Loading history...
947
				$share->setPassword($this->hasher->hash($share->getPassword()));
948
949
				return true;
950
			}
951
		}
952
953
		return false;
954
	}
955
956
	/**
957
	 * Delete all the children of this share
958
	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
959
	 *
960
	 * @param \OCP\Share\IShare $share
961
	 * @return \OCP\Share\IShare[] List of deleted shares
962
	 */
963
	protected function deleteChildren(\OCP\Share\IShare $share) {
964
		$deletedShares = [];
965
966
		$provider = $this->factory->getProviderForType($share->getShareType());
967
968
		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

968
		foreach ($provider->/** @scrutinizer ignore-call */ getChildren($share) as $child) {
Loading history...
969
			$deletedChildren = $this->deleteChildren($child);
970
			$deletedShares = array_merge($deletedShares, $deletedChildren);
971
972
			$provider->delete($child);
973
			$deletedShares[] = $child;
974
		}
975
976
		return $deletedShares;
977
	}
978
979
	/**
980
	 * Delete a share
981
	 *
982
	 * @param \OCP\Share\IShare $share
983
	 * @throws ShareNotFound
984
	 * @throws \InvalidArgumentException
985
	 */
986
	public function deleteShare(\OCP\Share\IShare $share) {
987
988
		try {
989
			$share->getFullId();
990
		} catch (\UnexpectedValueException $e) {
991
			throw new \InvalidArgumentException('Share does not have a full id');
992
		}
993
994
		$event = new GenericEvent($share);
995
		$this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

995
		$this->eventDispatcher->/** @scrutinizer ignore-call */ 
996
                          dispatch('OCP\Share::preUnshare', $event);

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

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

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

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

995
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::preUnshare', $event);
Loading history...
996
997
		// Get all children and delete them as well
998
		$deletedShares = $this->deleteChildren($share);
999
1000
		// Do the actual delete
1001
		$provider = $this->factory->getProviderForType($share->getShareType());
1002
		$provider->delete($share);
1003
1004
		// All the deleted shares caused by this delete
1005
		$deletedShares[] = $share;
1006
1007
		// Emit post hook
1008
		$event->setArgument('deletedShares', $deletedShares);
1009
		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
1010
	}
1011
1012
1013
	/**
1014
	 * Unshare a file as the recipient.
1015
	 * This can be different from a regular delete for example when one of
1016
	 * the users in a groups deletes that share. But the provider should
1017
	 * handle this.
1018
	 *
1019
	 * @param \OCP\Share\IShare $share
1020
	 * @param string $recipientId
1021
	 */
1022
	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
1023
		list($providerId, ) = $this->splitFullId($share->getFullId());
1024
		$provider = $this->factory->getProvider($providerId);
1025
1026
		$provider->deleteFromSelf($share, $recipientId);
1027
		$event = new GenericEvent($share);
1028
		$this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with $event. ( Ignorable by Annotation )

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

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

1028
		$this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ 'OCP\Share::postUnshareFromSelf', $event);
Loading history...
1029
	}
1030
1031
	public function restoreShare(IShare $share, string $recipientId): IShare {
1032
		list($providerId, ) = $this->splitFullId($share->getFullId());
1033
		$provider = $this->factory->getProvider($providerId);
1034
1035
		return $provider->restore($share, $recipientId);
1036
	}
1037
1038
	/**
1039
	 * @inheritdoc
1040
	 */
1041
	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1042
		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

1042
		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...
1043
			throw new \InvalidArgumentException('Can’t change target of link share');
1044
		}
1045
1046
		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

1046
		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...
1047
			throw new \InvalidArgumentException('Invalid recipient');
1048
		}
1049
1050
		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

1050
		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...
1051
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1052
			if (is_null($sharedWith)) {
1053
				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1054
			}
1055
			$recipient = $this->userManager->get($recipientId);
1056
			if (!$sharedWith->inGroup($recipient)) {
1057
				throw new \InvalidArgumentException('Invalid recipient');
1058
			}
1059
		}
1060
1061
		list($providerId, ) = $this->splitFullId($share->getFullId());
1062
		$provider = $this->factory->getProvider($providerId);
1063
1064
		$provider->move($share, $recipientId);
1065
	}
1066
1067
	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1068
		$providers = $this->factory->getAllProviders();
1069
1070
		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1071
			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1072
			foreach ($newShares as $fid => $data) {
1073
				if (!isset($shares[$fid])) {
1074
					$shares[$fid] = [];
1075
				}
1076
1077
				$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

1077
				$shares[$fid] = array_merge($shares[$fid], /** @scrutinizer ignore-type */ $data);
Loading history...
1078
			}
1079
			return $shares;
1080
		}, []);
1081
	}
1082
1083
	/**
1084
	 * @inheritdoc
1085
	 */
1086
	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1087
		if ($path !== null &&
1088
				!($path instanceof \OCP\Files\File) &&
1089
				!($path instanceof \OCP\Files\Folder)) {
1090
			throw new \InvalidArgumentException('invalid path');
1091
		}
1092
1093
		try {
1094
			$provider = $this->factory->getProviderForType($shareType);
1095
		} catch (ProviderException $e) {
1096
			return [];
1097
		}
1098
1099
		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1100
1101
		/*
1102
		 * Work around so we don't return expired shares but still follow
1103
		 * proper pagination.
1104
		 */
1105
1106
		$shares2 = [];
1107
1108
		while(true) {
1109
			$added = 0;
1110
			foreach ($shares as $share) {
1111
1112
				try {
1113
					$this->checkExpireDate($share);
1114
				} catch (ShareNotFound $e) {
1115
					//Ignore since this basically means the share is deleted
1116
					continue;
1117
				}
1118
1119
				$added++;
1120
				$shares2[] = $share;
1121
1122
				if (count($shares2) === $limit) {
1123
					break;
1124
				}
1125
			}
1126
1127
			// If we did not fetch more shares than the limit then there are no more shares
1128
			if (count($shares) < $limit) {
1129
				break;
1130
			}
1131
1132
			if (count($shares2) === $limit) {
1133
				break;
1134
			}
1135
1136
			// If there was no limit on the select we are done
1137
			if ($limit === -1) {
1138
				break;
1139
			}
1140
1141
			$offset += $added;
1142
1143
			// Fetch again $limit shares
1144
			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1145
1146
			// No more shares means we are done
1147
			if (empty($shares)) {
1148
				break;
1149
			}
1150
		}
1151
1152
		$shares = $shares2;
1153
1154
		return $shares;
1155
	}
1156
1157
	/**
1158
	 * @inheritdoc
1159
	 */
1160
	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1161
		try {
1162
			$provider = $this->factory->getProviderForType($shareType);
1163
		} catch (ProviderException $e) {
1164
			return [];
1165
		}
1166
1167
		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1168
1169
		// remove all shares which are already expired
1170
		foreach ($shares as $key => $share) {
1171
			try {
1172
				$this->checkExpireDate($share);
1173
			} catch (ShareNotFound $e) {
1174
				unset($shares[$key]);
1175
			}
1176
		}
1177
1178
		return $shares;
1179
	}
1180
1181
	/**
1182
	 * @inheritdoc
1183
	 */
1184
	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1185
		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1186
1187
		// Only get deleted shares
1188
		$shares = array_filter($shares, function(IShare $share) {
1189
			return $share->getPermissions() === 0;
1190
		});
1191
1192
		// Only get shares where the owner still exists
1193
		$shares = array_filter($shares, function (IShare $share) {
1194
			return $this->userManager->userExists($share->getShareOwner());
1195
		});
1196
1197
		return $shares;
1198
	}
1199
1200
	/**
1201
	 * @inheritdoc
1202
	 */
1203
	public function getShareById($id, $recipient = null) {
1204
		if ($id === null) {
1205
			throw new ShareNotFound();
1206
		}
1207
1208
		list($providerId, $id) = $this->splitFullId($id);
1209
1210
		try {
1211
			$provider = $this->factory->getProvider($providerId);
1212
		} catch (ProviderException $e) {
1213
			throw new ShareNotFound();
1214
		}
1215
1216
		$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

1216
		$share = $provider->getShareById(/** @scrutinizer ignore-type */ $id, $recipient);
Loading history...
1217
1218
		$this->checkExpireDate($share);
1219
1220
		return $share;
1221
	}
1222
1223
	/**
1224
	 * Get all the shares for a given path
1225
	 *
1226
	 * @param \OCP\Files\Node $path
1227
	 * @param int $page
1228
	 * @param int $perPage
1229
	 *
1230
	 * @return Share[]
1231
	 */
1232
	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
0 ignored issues
show
Unused Code introduced by
The parameter $page is not used and could be removed. ( Ignorable by Annotation )

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

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

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

Loading history...
Unused Code introduced by
The parameter $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

1232
	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

1232
	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...
1233
		return [];
1234
	}
1235
1236
	/**
1237
	 * Get the share by token possible with password
1238
	 *
1239
	 * @param string $token
1240
	 * @return Share
1241
	 *
1242
	 * @throws ShareNotFound
1243
	 */
1244
	public function getShareByToken($token) {
1245
		// tokens can't be valid local user names
1246
		if ($this->userManager->userExists($token)) {
1247
			throw new ShareNotFound();
1248
		}
1249
		$share = null;
1250
		try {
1251
			if($this->shareApiAllowLinks()) {
1252
				$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

1252
				$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...
1253
				$share = $provider->getShareByToken($token);
1254
			}
1255
		} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1256
		} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1257
		}
1258
1259
1260
		// If it is not a link share try to fetch a federated share by token
1261
		if ($share === null) {
1262
			try {
1263
				$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

1263
				$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...
1264
				$share = $provider->getShareByToken($token);
1265
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1266
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1267
			}
1268
		}
1269
1270
		// If it is not a link share try to fetch a mail share by token
1271
		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

1271
		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...
1272
			try {
1273
				$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

1273
				$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...
1274
				$share = $provider->getShareByToken($token);
1275
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1276
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1277
			}
1278
		}
1279
1280
		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

1280
		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...
1281
			try {
1282
				$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

1282
				$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...
1283
				$share = $provider->getShareByToken($token);
1284
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1285
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1286
			}
1287
		}
1288
1289
		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

1289
		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...
1290
			try {
1291
				$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

1291
				$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...
1292
				$share = $provider->getShareByToken($token);
1293
			} catch (ProviderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1294
			} catch (ShareNotFound $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1295
			}
1296
		}
1297
1298
		if ($share === null) {
1299
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1300
		}
1301
1302
		$this->checkExpireDate($share);
1303
1304
		/*
1305
		 * Reduce the permissions for link shares if public upload is not enabled
1306
		 */
1307
		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

1307
		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...
1308
			!$this->shareApiLinkAllowPublicUpload()) {
1309
			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1310
		}
1311
1312
		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...
1313
	}
1314
1315
	protected function checkExpireDate($share) {
1316
		if ($share->isExpired()) {
1317
			$this->deleteShare($share);
1318
			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1319
		}
1320
1321
	}
1322
1323
	/**
1324
	 * Verify the password of a public share
1325
	 *
1326
	 * @param \OCP\Share\IShare $share
1327
	 * @param string $password
1328
	 * @return bool
1329
	 */
1330
	public function checkPassword(\OCP\Share\IShare $share, $password) {
1331
		$passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_LINK has been deprecated: 17.0.0 - use IShare::TYPE_LINK instead ( Ignorable by Annotation )

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

1331
		$passwordProtected = $share->getShareType() !== /** @scrutinizer ignore-deprecated */ \OCP\Share::SHARE_TYPE_LINK

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

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

Loading history...
1332
			|| $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

1332
			|| $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...
1333
		if (!$passwordProtected) {
1334
			//TODO maybe exception?
1335
			return false;
1336
		}
1337
1338
		if ($password === null || $share->getPassword() === null) {
0 ignored issues
show
introduced by
The condition $share->getPassword() === null is always false.
Loading history...
1339
			return false;
1340
		}
1341
1342
		$newHash = '';
1343
		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1344
			return false;
1345
		}
1346
1347
		if (!empty($newHash)) {
1348
			$share->setPassword($newHash);
1349
			$provider = $this->factory->getProviderForType($share->getShareType());
1350
			$provider->update($share);
1351
		}
1352
1353
		return true;
1354
	}
1355
1356
	/**
1357
	 * @inheritdoc
1358
	 */
1359
	public function userDeleted($uid) {
1360
		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
0 ignored issues
show
Deprecated Code introduced by
The constant OC\Share\Constants::SHARE_TYPE_USER has been deprecated: 17.0.0 - use IShare::TYPE_USER instead ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

1360
		$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...
1361
1362
		foreach ($types as $type) {
1363
			try {
1364
				$provider = $this->factory->getProviderForType($type);
1365
			} catch (ProviderException $e) {
1366
				continue;
1367
			}
1368
			$provider->userDeleted($uid, $type);
1369
		}
1370
	}
1371
1372
	/**
1373
	 * @inheritdoc
1374
	 */
1375
	public function groupDeleted($gid) {
1376
		$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

1376
		$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...
1377
		$provider->groupDeleted($gid);
1378
	}
1379
1380
	/**
1381
	 * @inheritdoc
1382
	 */
1383
	public function userDeletedFromGroup($uid, $gid) {
1384
		$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

1384
		$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...
1385
		$provider->userDeletedFromGroup($uid, $gid);
1386
	}
1387
1388
	/**
1389
	 * Get access list to a path. This means
1390
	 * all the users that can access a given path.
1391
	 *
1392
	 * Consider:
1393
	 * -root
1394
	 * |-folder1 (23)
1395
	 *  |-folder2 (32)
1396
	 *   |-fileA (42)
1397
	 *
1398
	 * fileA is shared with user1 and user1@server1
1399
	 * folder2 is shared with group2 (user4 is a member of group2)
1400
	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1401
	 *
1402
	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1403
	 * [
1404
	 *  users  => [
1405
	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1406
	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1407
	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1408
	 *  ],
1409
	 *  remote => [
1410
	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1411
	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1412
	 *  ],
1413
	 *  public => bool
1414
	 *  mail => bool
1415
	 * ]
1416
	 *
1417
	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1418
	 * [
1419
	 *  users  => ['user1', 'user2', 'user4'],
1420
	 *  remote => bool,
1421
	 *  public => bool
1422
	 *  mail => bool
1423
	 * ]
1424
	 *
1425
	 * This is required for encryption/activity
1426
	 *
1427
	 * @param \OCP\Files\Node $path
1428
	 * @param bool $recursive Should we check all parent folders as well
1429
	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1430
	 * @return array
1431
	 */
1432
	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1433
		$owner = $path->getOwner();
1434
1435
		if ($owner === null) {
1436
			return [];
1437
		}
1438
1439
		$owner = $owner->getUID();
1440
1441
		if ($currentAccess) {
1442
			$al = ['users' => [], 'remote' => [], 'public' => false];
1443
		} else {
1444
			$al = ['users' => [], 'remote' => false, 'public' => false];
1445
		}
1446
		if (!$this->userManager->userExists($owner)) {
1447
			return $al;
1448
		}
1449
1450
		//Get node for the owner and correct the owner in case of external storages
1451
		$userFolder = $this->rootFolder->getUserFolder($owner);
1452
		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1453
			$nodes = $userFolder->getById($path->getId());
1454
			$path = array_shift($nodes);
1455
			if ($path->getOwner() === null) {
1456
				return [];
1457
			}
1458
			$owner = $path->getOwner()->getUID();
1459
		}
1460
1461
		$providers = $this->factory->getAllProviders();
1462
1463
		/** @var Node[] $nodes */
1464
		$nodes = [];
1465
1466
1467
		if ($currentAccess) {
1468
			$ownerPath = $path->getPath();
1469
			$ownerPath = explode('/', $ownerPath, 4);
1470
			if (count($ownerPath) < 4) {
1471
				$ownerPath = '';
1472
			} else {
1473
				$ownerPath = $ownerPath[3];
1474
			}
1475
			$al['users'][$owner] = [
1476
				'node_id' => $path->getId(),
1477
				'node_path' => '/' . $ownerPath,
1478
			];
1479
		} else {
1480
			$al['users'][] = $owner;
1481
		}
1482
1483
		// Collect all the shares
1484
		while ($path->getPath() !== $userFolder->getPath()) {
1485
			$nodes[] = $path;
1486
			if (!$recursive) {
1487
				break;
1488
			}
1489
			$path = $path->getParent();
1490
		}
1491
1492
		foreach ($providers as $provider) {
1493
			$tmp = $provider->getAccessList($nodes, $currentAccess);
1494
1495
			foreach ($tmp as $k => $v) {
1496
				if (isset($al[$k])) {
1497
					if (is_array($al[$k])) {
1498
						if ($currentAccess) {
1499
							$al[$k] += $v;
1500
						} else {
1501
							$al[$k] = array_merge($al[$k], $v);
1502
							$al[$k] = array_unique($al[$k]);
1503
							$al[$k] = array_values($al[$k]);
1504
						}
1505
					} else {
1506
						$al[$k] = $al[$k] || $v;
1507
					}
1508
				} else {
1509
					$al[$k] = $v;
1510
				}
1511
			}
1512
		}
1513
1514
		return $al;
1515
	}
1516
1517
	/**
1518
	 * Create a new share
1519
	 * @return \OCP\Share\IShare
1520
	 */
1521
	public function newShare() {
1522
		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1523
	}
1524
1525
	/**
1526
	 * Is the share API enabled
1527
	 *
1528
	 * @return bool
1529
	 */
1530
	public function shareApiEnabled() {
1531
		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1532
	}
1533
1534
	/**
1535
	 * Is public link sharing enabled
1536
	 *
1537
	 * @return bool
1538
	 */
1539
	public function shareApiAllowLinks() {
1540
		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1541
	}
1542
1543
	/**
1544
	 * Is password on public link requires
1545
	 *
1546
	 * @return bool
1547
	 */
1548
	public function shareApiLinkEnforcePassword() {
1549
		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1550
	}
1551
1552
	/**
1553
	 * Is default expire date enabled
1554
	 *
1555
	 * @return bool
1556
	 */
1557
	public function shareApiLinkDefaultExpireDate() {
1558
		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1559
	}
1560
1561
	/**
1562
	 * Is default expire date enforced
1563
	 *`
1564
	 * @return bool
1565
	 */
1566
	public function shareApiLinkDefaultExpireDateEnforced() {
1567
		return $this->shareApiLinkDefaultExpireDate() &&
1568
			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1569
	}
1570
1571
	/**
1572
	 * Number of default expire days
1573
	 *shareApiLinkAllowPublicUpload
1574
	 * @return int
1575
	 */
1576
	public function shareApiLinkDefaultExpireDays() {
1577
		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1578
	}
1579
1580
	/**
1581
	 * Allow public upload on link shares
1582
	 *
1583
	 * @return bool
1584
	 */
1585
	public function shareApiLinkAllowPublicUpload() {
1586
		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1587
	}
1588
1589
	/**
1590
	 * check if user can only share with group members
1591
	 * @return bool
1592
	 */
1593
	public function shareWithGroupMembersOnly() {
1594
		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1595
	}
1596
1597
	/**
1598
	 * Check if users can share with groups
1599
	 * @return bool
1600
	 */
1601
	public function allowGroupSharing() {
1602
		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1603
	}
1604
1605
	/**
1606
	 * Copied from \OC_Util::isSharingDisabledForUser
1607
	 *
1608
	 * TODO: Deprecate fuction from OC_Util
1609
	 *
1610
	 * @param string $userId
1611
	 * @return bool
1612
	 */
1613
	public function sharingDisabledForUser($userId) {
1614
		if ($userId === null) {
0 ignored issues
show
introduced by
The condition $userId === null is always false.
Loading history...
1615
			return false;
1616
		}
1617
1618
		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1619
			return $this->sharingDisabledForUsersCache[$userId];
1620
		}
1621
1622
		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1623
			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1624
			$excludedGroups = json_decode($groupsList);
1625
			if (is_null($excludedGroups)) {
1626
				$excludedGroups = explode(',', $groupsList);
1627
				$newValue = json_encode($excludedGroups);
1628
				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1629
			}
1630
			$user = $this->userManager->get($userId);
1631
			$usersGroups = $this->groupManager->getUserGroupIds($user);
1632
			if (!empty($usersGroups)) {
1633
				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1634
				// if the user is only in groups which are disabled for sharing then
1635
				// sharing is also disabled for the user
1636
				if (empty($remainingGroups)) {
1637
					$this->sharingDisabledForUsersCache[$userId] = true;
1638
					return true;
1639
				}
1640
			}
1641
		}
1642
1643
		$this->sharingDisabledForUsersCache[$userId] = false;
1644
		return false;
1645
	}
1646
1647
	/**
1648
	 * @inheritdoc
1649
	 */
1650
	public function outgoingServer2ServerSharesAllowed() {
1651
		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1652
	}
1653
1654
	/**
1655
	 * @inheritdoc
1656
	 */
1657
	public function outgoingServer2ServerGroupSharesAllowed() {
1658
		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1659
	}
1660
1661
	/**
1662
	 * @inheritdoc
1663
	 */
1664
	public function shareProviderExists($shareType) {
1665
		try {
1666
			$this->factory->getProviderForType($shareType);
1667
		} catch (ProviderException $e) {
1668
			return false;
1669
		}
1670
1671
		return true;
1672
	}
1673
1674
	public function getAllShares(): iterable {
1675
		$providers = $this->factory->getAllProviders();
1676
1677
		foreach ($providers as $provider) {
1678
			yield from $provider->getAllShares();
1679
		}
1680
	}
1681
}
1682