Passed
Push — master ( f5728f...337cd2 )
by Morris
75:46 queued 62:51
created

Share::tryHttpPostToShareEndpoint()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 21
nc 7
nop 3
dl 0
loc 32
rs 9.2728
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Bernhard Reiter <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Björn Schießle <[email protected]>
9
 * @author Christopher Schäpers <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Jörn Friedrich Dreyer <[email protected]>
12
 * @author Lukas Reschke <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Robin McCorkell <[email protected]>
16
 * @author Roeland Jago Douma <[email protected]>
17
 * @author Sebastian Döll <[email protected]>
18
 * @author Stefan Weil <[email protected]>
19
 * @author Thomas Müller <[email protected]>
20
 * @author Torben Dannhauer <[email protected]>
21
 * @author Vincent Petry <[email protected]>
22
 * @author Volkan Gezer <[email protected]>
23
 *
24
 * @license AGPL-3.0
25
 *
26
 * This code is free software: you can redistribute it and/or modify
27
 * it under the terms of the GNU Affero General Public License, version 3,
28
 * as published by the Free Software Foundation.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
 * GNU Affero General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU Affero General Public License, version 3,
36
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
37
 *
38
 */
39
40
namespace OC\Share;
41
42
use OCP\DB\QueryBuilder\IQueryBuilder;
43
use OCP\IConfig;
44
use OCP\ILogger;
45
use OCP\Util;
46
47
/**
48
 * This class provides the ability for apps to share their content between users.
49
 * Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
50
 *
51
 * It provides the following hooks:
52
 *  - post_shared
53
 */
54
class Share extends Constants {
55
56
	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
57
	 * Construct permissions for share() and setPermissions with Or (|) e.g.
58
	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
59
	 *
60
	 * Check if permission is granted with And (&) e.g. Check if delete is
61
	 * granted: if ($permissions & PERMISSION_DELETE)
62
	 *
63
	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
64
	 * permission: $permissions &= ~PERMISSION_UPDATE
65
	 *
66
	 * Apps are required to handle permissions on their own, this class only
67
	 * stores and manages the permissions of shares
68
	 * @see lib/public/constants.php
69
	 */
70
71
	/**
72
	 * Register a sharing backend class that implements OCP\Share_Backend for an item type
73
	 * @param string $itemType Item type
74
	 * @param string $class Backend class
75
	 * @param string $collectionOf (optional) Depends on item type
76
	 * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
77
	 * @return boolean true if backend is registered or false if error
78
	 */
79
	public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
80
		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
81
			if (!isset(self::$backendTypes[$itemType])) {
82
				self::$backendTypes[$itemType] = array(
83
					'class' => $class,
84
					'collectionOf' => $collectionOf,
85
					'supportedFileExtensions' => $supportedFileExtensions
86
				);
87
				if(count(self::$backendTypes) === 1) {
88
					Util::addScript('core', 'merged-share-backend');
89
				}
90
				return true;
91
			}
92
			\OCP\Util::writeLog('OCP\Share',
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

92
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share',

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...
93
				'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
94
				.' is already registered for '.$itemType,
95
				ILogger::WARN);
96
		}
97
		return false;
98
	}
99
100
	/**
101
	 * Get the items of item type shared with the current user
102
	 * @param string $itemType
103
	 * @param int $format (optional) Format type must be defined by the backend
104
	 * @param mixed $parameters (optional)
105
	 * @param int $limit Number of items to return (optional) Returns all by default
106
	 * @param boolean $includeCollections (optional)
107
	 * @return mixed Return depends on format
108
	 */
109
	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
110
											  $parameters = null, $limit = -1, $includeCollections = false) {
111
		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
112
			$parameters, $limit, $includeCollections);
113
	}
114
115
	/**
116
	 * Get the items of item type shared with a user
117
	 * @param string $itemType
118
	 * @param string $user id for which user we want the shares
119
	 * @param int $format (optional) Format type must be defined by the backend
120
	 * @param mixed $parameters (optional)
121
	 * @param int $limit Number of items to return (optional) Returns all by default
122
	 * @param boolean $includeCollections (optional)
123
	 * @return mixed Return depends on format
124
	 */
125
	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
126
												  $parameters = null, $limit = -1, $includeCollections = false) {
127
		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
128
			$parameters, $limit, $includeCollections);
129
	}
130
131
	/**
132
	 * Get the item of item type shared with a given user by source
133
	 * @param string $itemType
134
	 * @param string $itemSource
135
	 * @param string $user User to whom the item was shared
136
	 * @param string $owner Owner of the share
137
	 * @param int $shareType only look for a specific share type
138
	 * @return array Return list of items with file_target, permissions and expiration
139
	 */
140
	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
141
		$shares = array();
142
		$fileDependent = false;
143
144
		$where = 'WHERE';
145
		$fileDependentWhere = '';
146
		if ($itemType === 'file' || $itemType === 'folder') {
147
			$fileDependent = true;
148
			$column = 'file_source';
149
			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
150
			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
151
		} else {
152
			$column = 'item_source';
153
		}
154
155
		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
156
157
		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
158
		$arguments = array($itemSource, $itemType);
159
		// for link shares $user === null
160
		if ($user !== null) {
0 ignored issues
show
introduced by
The condition $user !== null is always true.
Loading history...
161
			$where .= ' AND `share_with` = ? ';
162
			$arguments[] = $user;
163
		}
164
165
		if ($shareType !== null) {
166
			$where .= ' AND `share_type` = ? ';
167
			$arguments[] = $shareType;
168
		}
169
170
		if ($owner !== null) {
171
			$where .= ' AND `uid_owner` = ? ';
172
			$arguments[] = $owner;
173
		}
174
175
		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
176
177
		$result = \OC_DB::executeAudited($query, $arguments);
178
179
		while ($row = $result->fetchRow()) {
180
			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
181
				continue;
182
			}
183
			if ($fileDependent && (int)$row['file_parent'] === -1) {
184
				// if it is a mount point we need to get the path from the mount manager
185
				$mountManager = \OC\Files\Filesystem::getMountManager();
186
				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
187
				if (!empty($mountPoint)) {
188
					$path = $mountPoint[0]->getMountPoint();
189
					$path = trim($path, '/');
190
					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
191
					$row['path'] = $path;
192
				} else {
193
					\OC::$server->getLogger()->warning(
194
						'Could not resolve mount point for ' . $row['storage_id'],
195
						['app' => 'OCP\Share']
196
					);
197
				}
198
			}
199
			$shares[] = $row;
200
		}
201
202
		//if didn't found a result than let's look for a group share.
203
		if(empty($shares) && $user !== null) {
204
			$userObject = \OC::$server->getUserManager()->get($user);
205
			$groups = [];
206
			if ($userObject) {
207
				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
208
			}
209
210
			if (!empty($groups)) {
211
				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
212
				$arguments = array($itemSource, $itemType, $groups);
213
				$types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
214
215
				if ($owner !== null) {
216
					$where .= ' AND `uid_owner` = ?';
217
					$arguments[] = $owner;
218
					$types[] = null;
219
				}
220
221
				// TODO: inject connection, hopefully one day in the future when this
222
				// class isn't static anymore...
223
				$conn = \OC::$server->getDatabaseConnection();
224
				$result = $conn->executeQuery(
225
					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
226
					$arguments,
227
					$types
228
				);
229
230
				while ($row = $result->fetch()) {
231
					$shares[] = $row;
232
				}
233
			}
234
		}
235
236
		return $shares;
237
238
	}
239
240
	/**
241
	 * Get the item of item type shared with the current user by source
242
	 * @param string $itemType
243
	 * @param string $itemSource
244
	 * @param int $format (optional) Format type must be defined by the backend
245
	 * @param mixed $parameters
246
	 * @param boolean $includeCollections
247
	 * @param string $shareWith (optional) define against which user should be checked, default: current user
248
	 * @return array
249
	 */
250
	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
251
													 $parameters = null, $includeCollections = false, $shareWith = null) {
252
		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
253
		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
254
			$parameters, 1, $includeCollections, true);
255
	}
256
257
	/**
258
	 * Based on the given token the share information will be returned - password protected shares will be verified
259
	 * @param string $token
260
	 * @param bool $checkPasswordProtection
261
	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
262
	 */
263
	public static function getShareByToken($token, $checkPasswordProtection = true) {
264
		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
265
		$result = $query->execute(array($token));
266
		if ($result === false) {
267
			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

267
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, ILogger::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...
268
		}
269
		$row = $result->fetchRow();
270
		if ($row === false) {
271
			return false;
272
		}
273
		if (is_array($row) and self::expireItem($row)) {
274
			return false;
275
		}
276
277
		// password protected shares need to be authenticated
278
		if ($checkPasswordProtection && !\OC\Share\Share::checkPasswordProtectedShare($row)) {
279
			return false;
280
		}
281
282
		return $row;
283
	}
284
285
	/**
286
	 * Get the shared items of item type owned by the current user
287
	 * @param string $itemType
288
	 * @param int $format (optional) Format type must be defined by the backend
289
	 * @param mixed $parameters
290
	 * @param int $limit Number of items to return (optional) Returns all by default
291
	 * @param boolean $includeCollections
292
	 * @return mixed Return depends on format
293
	 */
294
	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
295
										  $limit = -1, $includeCollections = false) {
296
		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
297
			$parameters, $limit, $includeCollections);
298
	}
299
300
	/**
301
	 * Get the shared item of item type owned by the current user
302
	 * @param string $itemType
303
	 * @param string $itemSource
304
	 * @param int $format (optional) Format type must be defined by the backend
305
	 * @param mixed $parameters
306
	 * @param boolean $includeCollections
307
	 * @return mixed Return depends on format
308
	 */
309
	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
310
										 $parameters = null, $includeCollections = false) {
311
		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
312
			$parameters, -1, $includeCollections);
313
	}
314
315
	/**
316
	 * Share an item with a user, group, or via private link
317
	 * @param string $itemType
318
	 * @param string $itemSource
319
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
320
	 * @param string $shareWith User or group the item is being shared with
321
	 * @param int $permissions CRUDS
322
	 * @param string $itemSourceName
323
	 * @param \DateTime|null $expirationDate
324
	 * @param bool|null $passwordChanged
325
	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
326
	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
327
	 * @throws \Exception
328
	 * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
329
	 * @deprecated 14.0.0 TESTS ONLY - this methods is as of 2018-06 only used by tests
330
	 */
331
	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
332
333
		$backend = self::getBackend($itemType);
334
		$l = \OC::$server->getL10N('lib');
335
336
		if ($backend->isShareTypeAllowed($shareType) === false) {
337
			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
338
			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
339
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

339
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), ILogger::DEBUG);

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...
340
			throw new \Exception($message_t);
341
		}
342
343
		$uidOwner = \OC_User::getUser();
344
		$shareWithinGroupOnly = \OC::$server->getConfig()->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
345
346
		if (is_null($itemSourceName)) {
347
			$itemSourceName = $itemSource;
348
		}
349
		$itemName = $itemSourceName;
350
351
		// check if file can be shared
352
		if ($itemType === 'file' or $itemType === 'folder') {
353
			$path = \OC\Files\Filesystem::getPath($itemSource);
0 ignored issues
show
Bug introduced by
$itemSource of type string is incompatible with the type integer expected by parameter $id of OC\Files\Filesystem::getPath(). ( Ignorable by Annotation )

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

353
			$path = \OC\Files\Filesystem::getPath(/** @scrutinizer ignore-type */ $itemSource);
Loading history...
354
			$itemName = $path;
355
356
			// verify that the file exists before we try to share it
357
			if (!$path) {
358
				$message = 'Sharing %s failed, because the file does not exist';
359
				$message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
360
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

360
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);

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...
361
				throw new \Exception($message_t);
362
			}
363
			// verify that the user has share permission
364
			if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::isSharingDisabledForUser() has been deprecated: 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser ( Ignorable by Annotation )

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

364
			if (!\OC\Files\Filesystem::isSharable($path) || /** @scrutinizer ignore-deprecated */ \OCP\Util::isSharingDisabledForUser()) {

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...
365
				$message = 'You are not allowed to share %s';
366
				$message_t = $l->t('You are not allowed to share %s', [$path]);
367
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

367
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $path), ILogger::DEBUG);

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...
368
				throw new \Exception($message_t);
369
			}
370
		}
371
372
		//verify that we don't share a folder which already contains a share mount point
373
		if ($itemType === 'folder') {
374
			$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
375
			$mountManager = \OC\Files\Filesystem::getMountManager();
376
			$mounts = $mountManager->findIn($path);
377
			foreach ($mounts as $mount) {
378
				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
379
					$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
380
					\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

380
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);

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...
381
					throw new \Exception($message);
382
				}
383
384
			}
385
		}
386
387
		// single file shares should never have delete permissions
388
		if ($itemType === 'file') {
389
			$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
390
		}
391
392
		//Validate expirationDate
393
		if ($expirationDate !== null) {
394
			try {
395
				/*
396
				 * Reuse the validateExpireDate.
397
				 * We have to pass time() since the second arg is the time
398
				 * the file was shared, since it is not shared yet we just use
399
				 * the current time.
400
				 */
401
				$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
402
			} catch (\Exception $e) {
403
				throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
404
			}
405
		}
406
407
		// Verify share type and sharing conditions are met
408
		if ($shareType === self::SHARE_TYPE_USER) {
409
			if ($shareWith == $uidOwner) {
410
				$message = 'Sharing %s failed, because you can not share with yourself';
411
				$message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
412
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

412
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);

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...
413
				throw new \Exception($message_t);
414
			}
415
			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
416
				$message = 'Sharing %1$s failed, because the user %2$s does not exist';
417
				$message_t = $l->t('Sharing %1$s failed, because the user %2$s does not exist', array($itemSourceName, $shareWith));
418
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

418
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
419
				throw new \Exception($message_t);
420
			}
421
			if ($shareWithinGroupOnly) {
422
				$userManager = \OC::$server->getUserManager();
423
				$groupManager = \OC::$server->getGroupManager();
424
				$userOwner = $userManager->get($uidOwner);
425
				$userShareWith = $userManager->get($shareWith);
426
				$groupsOwner = [];
427
				$groupsShareWith = [];
428
				if ($userOwner) {
429
					$groupsOwner = $groupManager->getUserGroupIds($userOwner);
430
				}
431
				if ($userShareWith) {
432
					$groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
433
				}
434
				$inGroup = array_intersect($groupsOwner, $groupsShareWith);
435
				if (empty($inGroup)) {
436
					$message = 'Sharing %1$s failed, because the user '
437
						.'%2$s is not a member of any groups that %3$s is a member of';
438
					$message_t = $l->t('Sharing %1$s failed, because the user %2$s is not a member of any groups that %3$s is a member of', array($itemName, $shareWith, $uidOwner));
439
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

439
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), ILogger::DEBUG);

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...
440
					throw new \Exception($message_t);
441
				}
442
			}
443
			// Check if the item source is already shared with the user, either from the same owner or a different user
444
			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
445
				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
446
				// Only allow the same share to occur again if it is the same
447
				// owner and is not a user share, this use case is for increasing
448
				// permissions for a specific user
449
				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
450
					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
451
					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
452
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

452
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
453
					throw new \Exception($message_t);
454
				}
455
			}
456
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
457
				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
458
				// Only allow the same share to occur again if it is the same
459
				// owner and is not a user share, this use case is for increasing
460
				// permissions for a specific user
461
				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
462
					$message = 'Sharing %1$s failed, because this item is already shared with user %2$s';
463
					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with user %2$s', array($itemSourceName, $shareWith));
464
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

464
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::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...
465
					throw new \Exception($message_t);
466
				}
467
			}
468
		} else if ($shareType === self::SHARE_TYPE_GROUP) {
469
			if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
470
				$message = 'Sharing %1$s failed, because the group %2$s does not exist';
471
				$message_t = $l->t('Sharing %1$s failed, because the group %2$s does not exist', array($itemSourceName, $shareWith));
472
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

472
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
473
				throw new \Exception($message_t);
474
			}
475
			if ($shareWithinGroupOnly) {
476
				$group = \OC::$server->getGroupManager()->get($shareWith);
477
				$user = \OC::$server->getUserManager()->get($uidOwner);
478
				if (!$group || !$user || !$group->inGroup($user)) {
0 ignored issues
show
introduced by
$group is of type OC\Group\Group, thus it always evaluated to true.
Loading history...
479
					$message = 'Sharing %1$s failed, because '
480
						. '%2$s is not a member of the group %3$s';
481
					$message_t = $l->t('Sharing %1$s failed, because %2$s is not a member of the group %3$s', array($itemSourceName, $uidOwner, $shareWith));
482
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

482
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), ILogger::DEBUG);

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...
483
					throw new \Exception($message_t);
484
				}
485
			}
486
			// Check if the item source is already shared with the group, either from the same owner or a different user
487
			// The check for each user in the group is done inside the put() function
488
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
489
				null, self::FORMAT_NONE, null, 1, true, true)) {
490
491
				if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
492
					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
493
					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
494
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

494
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
495
					throw new \Exception($message_t);
496
				}
497
			}
498
			// Convert share with into an array with the keys group and users
499
			$group = $shareWith;
500
			$shareWith = array();
501
			$shareWith['group'] = $group;
502
503
504
			$groupObject = \OC::$server->getGroupManager()->get($group);
505
			$userIds = [];
506
			if ($groupObject) {
0 ignored issues
show
introduced by
$groupObject is of type OC\Group\Group, thus it always evaluated to true.
Loading history...
507
				$users = $groupObject->searchUsers('', -1, 0);
508
				foreach ($users as $user) {
509
					$userIds[] = $user->getUID();
510
				}
511
			}
512
513
			$shareWith['users'] = array_diff($userIds, array($uidOwner));
514
		} else if ($shareType === self::SHARE_TYPE_LINK) {
515
			$updateExistingShare = false;
516
			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
517
518
				// IF the password is changed via the old ajax endpoint verify it before deleting the old share
519
				if ($passwordChanged === true) {
520
					self::verifyPassword($shareWith);
521
				}
522
523
				// when updating a link share
524
				// FIXME Don't delete link if we update it
525
				if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
526
					$uidOwner, self::FORMAT_NONE, null, 1)) {
527
					// remember old token
528
					$oldToken = $checkExists['token'];
529
					$oldPermissions = $checkExists['permissions'];
530
					//delete the old share
531
					Helper::delete($checkExists['id']);
532
					$updateExistingShare = true;
533
				}
534
535
				if ($passwordChanged === null) {
536
					// Generate hash of password - same method as user passwords
537
					if (is_string($shareWith) && $shareWith !== '') {
538
						self::verifyPassword($shareWith);
539
						$shareWith = \OC::$server->getHasher()->hash($shareWith);
540
					} else {
541
						// reuse the already set password, but only if we change permissions
542
						// otherwise the user disabled the password protection
543
						if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $oldPermissions does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug Best Practice introduced by
The expression $checkExists of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
544
							$shareWith = $checkExists['share_with'];
545
						}
546
					}
547
				} else {
548
					if ($passwordChanged === true) {
549
						if (is_string($shareWith) && $shareWith !== '') {
550
							self::verifyPassword($shareWith);
551
							$shareWith = \OC::$server->getHasher()->hash($shareWith);
552
						}
553
					} else if ($updateExistingShare) {
554
						$shareWith = $checkExists['share_with'];
555
					}
556
				}
557
558
				if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
559
					$message = 'You need to provide a password to create a public link, only protected links are allowed';
560
					$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
561
					\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

561
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);

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...
562
					throw new \Exception($message_t);
563
				}
564
565
				if ($updateExistingShare === false &&
566
					self::isDefaultExpireDateEnabled() &&
567
					empty($expirationDate)) {
568
					$expirationDate = Helper::calcExpireDate();
569
				}
570
571
				// Generate token
572
				if (isset($oldToken)) {
573
					$token = $oldToken;
574
				} else {
575
					$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
576
						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
577
					);
578
				}
579
				$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
580
					null, $token, $itemSourceName, $expirationDate);
581
				if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
582
					return $token;
583
				} else {
584
					return false;
585
				}
586
			}
587
			$message = 'Sharing %s failed, because sharing with links is not allowed';
588
			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
589
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

589
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);

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...
590
			throw new \Exception($message_t);
591
		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
592
593
			/*
594
			 * Check if file is not already shared with the remote user
595
			 */
596
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
0 ignored issues
show
Unused Code introduced by
The assignment to $checkExists is dead and can be removed.
Loading history...
597
				$shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
598
					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
599
					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
600
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

600
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
601
					throw new \Exception($message_t);
602
			}
603
604
			// don't allow federated shares if source and target server are the same
605
			list($user, $remote) = Helper::splitUserRemote($shareWith);
606
			$currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
607
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
608
			if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
609
				$message = 'Not allowed to create a federated share with the same user.';
610
				$message_t = $l->t('Not allowed to create a federated share with the same user');
611
				\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

611
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);

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...
612
				throw new \Exception($message_t);
613
			}
614
615
			$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
616
				\OCP\Security\ISecureRandom::CHAR_DIGITS);
617
618
			$shareWith = $user . '@' . $remote;
619
			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
620
621
			$send = false;
622
			if ($shareId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shareId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
623
				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
624
			}
625
626
			if ($send === false) {
627
				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
628
				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
629
				$message_t = $l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
630
				throw new \Exception($message_t);
631
			}
632
633
			return $send;
634
		} else {
635
			// Future share types need to include their own conditions
636
			$message = 'Share type %1$s is not valid for %2$s';
637
			$message_t = $l->t('Share type %1$s is not valid for %2$s', array($shareType, $itemSource));
638
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

638
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), ILogger::DEBUG);

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...
639
			throw new \Exception($message_t);
640
		}
641
642
		// Put the item into the database
643
		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
0 ignored issues
show
Bug introduced by
It seems like $shareWith can also be of type array; however, parameter $shareWith of OC\Share\Share::put() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

643
		$result = self::put($itemType, $itemSource, $shareType, /** @scrutinizer ignore-type */ $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
Loading history...
644
645
		return $result ? true : false;
646
	}
647
648
	/**
649
	 * Unshare an item from a user, group, or delete a private link
650
	 * @param string $itemType
651
	 * @param string $itemSource
652
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
653
	 * @param string $shareWith User or group the item is being shared with
654
	 * @param string $owner owner of the share, if null the current user is used
655
	 * @return boolean true on success or false on failure
656
	 */
657
	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
658
659
		// check if it is a valid itemType
660
		self::getBackend($itemType);
661
662
		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
663
664
		$toDelete = array();
665
		$newParent = null;
666
		$currentUser = $owner ? $owner : \OC_User::getUser();
667
		foreach ($items as $item) {
668
			// delete the item with the expected share_type and owner
669
			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
670
				$toDelete = $item;
671
				// if there is more then one result we don't have to delete the children
672
				// but update their parent. For group shares the new parent should always be
673
				// the original group share and not the db entry with the unique name
674
			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
675
				$newParent = $item['parent'];
676
			} else {
677
				$newParent = $item['id'];
678
			}
679
		}
680
681
		if (!empty($toDelete)) {
682
			self::unshareItem($toDelete, $newParent);
683
			return true;
684
		}
685
		return false;
686
	}
687
688
	/**
689
	 * sent status if users got informed by mail about share
690
	 * @param string $itemType
691
	 * @param string $itemSource
692
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
693
	 * @param string $recipient with whom was the file shared
694
	 * @param boolean $status
695
	 */
696
	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
697
		$status = $status ? 1 : 0;
698
699
		$query = \OC_DB::prepare(
700
			'UPDATE `*PREFIX*share`
701
					SET `mail_send` = ?
702
					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
703
704
		$result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
705
706
		if($result === false) {
707
			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

707
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', ILogger::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...
708
		}
709
	}
710
711
	/**
712
	 * validate expiration date if it meets all constraints
713
	 *
714
	 * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
715
	 * @param string $shareTime timestamp when the file was shared
716
	 * @param string $itemType
717
	 * @param string $itemSource
718
	 * @return \DateTime validated date
719
	 * @throws \Exception when the expire date is in the past or further in the future then the enforced date
720
	 */
721
	private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
722
		$l = \OC::$server->getL10N('lib');
723
		$date = new \DateTime($expireDate);
724
		$today = new \DateTime('now');
725
726
		// if the user doesn't provide a share time we need to get it from the database
727
		// fall-back mode to keep API stable, because the $shareTime parameter was added later
728
		$defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
729
		if ($defaultExpireDateEnforced && $shareTime === null) {
0 ignored issues
show
introduced by
The condition $shareTime === null is always false.
Loading history...
730
			$items = self::getItemShared($itemType, $itemSource);
731
			$firstItem = reset($items);
732
			$shareTime = (int)$firstItem['stime'];
733
		}
734
735
		if ($defaultExpireDateEnforced) {
736
			// initialize max date with share time
737
			$maxDate = new \DateTime();
738
			$maxDate->setTimestamp($shareTime);
0 ignored issues
show
Bug introduced by
$shareTime of type string is incompatible with the type integer expected by parameter $unixtimestamp of DateTime::setTimestamp(). ( Ignorable by Annotation )

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

738
			$maxDate->setTimestamp(/** @scrutinizer ignore-type */ $shareTime);
Loading history...
739
			$maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
740
			$maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
741
			if ($date > $maxDate) {
742
				$warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
743
				$warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
744
				\OCP\Util::writeLog('OCP\Share', $warning, ILogger::WARN);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

744
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', $warning, ILogger::WARN);

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...
745
				throw new \Exception($warning_t);
746
			}
747
		}
748
749
		if ($date < $today) {
750
			$message = 'Cannot set expiration date. Expiration date is in the past';
751
			$message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
752
			\OCP\Util::writeLog('OCP\Share', $message, ILogger::WARN);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

752
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', $message, ILogger::WARN);

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...
753
			throw new \Exception($message_t);
754
		}
755
756
		return $date;
757
	}
758
759
	/**
760
	 * Checks whether a share has expired, calls unshareItem() if yes.
761
	 * @param array $item Share data (usually database row)
762
	 * @return boolean True if item was expired, false otherwise.
763
	 */
764
	protected static function expireItem(array $item) {
765
766
		$result = false;
767
768
		// only use default expiration date for link shares
769
		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
770
771
			// calculate expiration date
772
			if (!empty($item['expiration'])) {
773
				$userDefinedExpire = new \DateTime($item['expiration']);
774
				$expires = $userDefinedExpire->getTimestamp();
775
			} else {
776
				$expires = null;
777
			}
778
779
780
			// get default expiration settings
781
			$defaultSettings = Helper::getDefaultExpireSetting();
782
			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
783
784
785
			if (is_int($expires)) {
786
				$now = time();
787
				if ($now > $expires) {
788
					self::unshareItem($item);
789
					$result = true;
790
				}
791
			}
792
		}
793
		return $result;
794
	}
795
796
	/**
797
	 * Unshares a share given a share data array
798
	 * @param array $item Share data (usually database row)
799
	 * @param int $newParent parent ID
800
	 * @return null
801
	 */
802
	protected static function unshareItem(array $item, $newParent = null) {
803
804
		$shareType = (int)$item['share_type'];
805
		$shareWith = null;
806
		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
807
			$shareWith = $item['share_with'];
808
		}
809
810
		// Pass all the vars we have for now, they may be useful
811
		$hookParams = array(
812
			'id'            => $item['id'],
813
			'itemType'      => $item['item_type'],
814
			'itemSource'    => $item['item_source'],
815
			'shareType'     => $shareType,
816
			'shareWith'     => $shareWith,
817
			'itemParent'    => $item['parent'],
818
			'uidOwner'      => $item['uid_owner'],
819
		);
820
		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
821
			$hookParams['fileSource'] = $item['file_source'];
822
			$hookParams['fileTarget'] = $item['file_target'];
823
		}
824
825
		\OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
826
		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
827
		$deletedShares[] = $hookParams;
828
		$hookParams['deletedShares'] = $deletedShares;
829
		\OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
830
		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
831
			list(, $remote) = Helper::splitUserRemote($item['share_with']);
832
			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
833
		}
834
	}
835
836
	/**
837
	 * Get the backend class for the specified item type
838
	 * @param string $itemType
839
	 * @throws \Exception
840
	 * @return \OCP\Share_Backend
841
	 */
842
	public static function getBackend($itemType) {
843
		$l = \OC::$server->getL10N('lib');
844
		if (isset(self::$backends[$itemType])) {
845
			return self::$backends[$itemType];
846
		} else if (isset(self::$backendTypes[$itemType]['class'])) {
847
			$class = self::$backendTypes[$itemType]['class'];
848
			if (class_exists($class)) {
849
				self::$backends[$itemType] = new $class;
850
				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
851
					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
852
					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
853
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

853
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::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...
854
					throw new \Exception($message_t);
855
				}
856
				return self::$backends[$itemType];
857
			} else {
858
				$message = 'Sharing backend %s not found';
859
				$message_t = $l->t('Sharing backend %s not found', array($class));
860
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

860
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::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...
861
				throw new \Exception($message_t);
862
			}
863
		}
864
		$message = 'Sharing backend for %s not found';
865
		$message_t = $l->t('Sharing backend for %s not found', array($itemType));
866
		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

866
		/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::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...
867
		throw new \Exception($message_t);
868
	}
869
870
	/**
871
	 * Check if resharing is allowed
872
	 * @return boolean true if allowed or false
873
	 *
874
	 * Resharing is allowed by default if not configured
875
	 */
876
	public static function isResharingAllowed() {
877
		if (!isset(self::$isResharingAllowed)) {
878
			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
879
				self::$isResharingAllowed = true;
880
			} else {
881
				self::$isResharingAllowed = false;
882
			}
883
		}
884
		return self::$isResharingAllowed;
885
	}
886
887
	/**
888
	 * Get a list of collection item types for the specified item type
889
	 * @param string $itemType
890
	 * @return array
891
	 */
892
	private static function getCollectionItemTypes($itemType) {
893
		$collectionTypes = array($itemType);
894
		foreach (self::$backendTypes as $type => $backend) {
895
			if (in_array($backend['collectionOf'], $collectionTypes)) {
896
				$collectionTypes[] = $type;
897
			}
898
		}
899
		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
900
		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
901
			unset($collectionTypes[0]);
902
		}
903
		// Return array if collections were found or the item type is a
904
		// collection itself - collections can be inside collections
905
		if (count($collectionTypes) > 0) {
906
			return $collectionTypes;
907
		}
908
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
909
	}
910
911
	/**
912
	 * Get the owners of items shared with a user.
913
	 *
914
	 * @param string $user The user the items are shared with.
915
	 * @param string $type The type of the items shared with the user.
916
	 * @param boolean $includeCollections Include collection item types (optional)
917
	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
918
	 * @return array
919
	 */
920
	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
921
		// First, we find out if $type is part of a collection (and if that collection is part of
922
		// another one and so on).
923
		$collectionTypes = array();
924
		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
925
			$collectionTypes[] = $type;
926
		}
927
928
		// Of these collection types, along with our original $type, we make a
929
		// list of the ones for which a sharing backend has been registered.
930
		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
931
		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
932
		$allMaybeSharedItems = array();
933
		foreach ($collectionTypes as $collectionType) {
934
			if (isset(self::$backends[$collectionType])) {
935
				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
936
					$collectionType,
937
					$user,
938
					self::FORMAT_NONE
939
				);
940
			}
941
		}
942
943
		$owners = array();
944
		if ($includeOwner) {
945
			$owners[] = $user;
946
		}
947
948
		// We take a look at all shared items of the given $type (or of the collections it is part of)
949
		// and find out their owners. Then, we gather the tags for the original $type from all owners,
950
		// and return them as elements of a list that look like "Tag (owner)".
951
		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
952
			foreach ($maybeSharedItems as $sharedItem) {
953
				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
954
					$owners[] = $sharedItem['uid_owner'];
955
				}
956
			}
957
		}
958
959
		return $owners;
960
	}
961
962
	/**
963
	 * Get shared items from the database
964
	 * @param string $itemType
965
	 * @param string $item Item source or target (optional)
966
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
967
	 * @param string $shareWith User or group the item is being shared with
968
	 * @param string $uidOwner User that is the owner of shared items (optional)
969
	 * @param int $format Format to convert items to with formatItems() (optional)
970
	 * @param mixed $parameters to pass to formatItems() (optional)
971
	 * @param int $limit Number of items to return, -1 to return all matches (optional)
972
	 * @param boolean $includeCollections Include collection item types (optional)
973
	 * @param boolean $itemShareWithBySource (optional)
974
	 * @param boolean $checkExpireDate
975
	 * @return array
976
	 *
977
	 * See public functions getItem(s)... for parameter usage
978
	 *
979
	 */
980
	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
981
									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
982
									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
983
		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
984
			return array();
985
		}
986
		$backend = self::getBackend($itemType);
987
		$collectionTypes = false;
988
		// Get filesystem root to add it to the file target and remove from the
989
		// file source, match file_source with the file cache
990
		if ($itemType == 'file' || $itemType == 'folder') {
991
			if(!is_null($uidOwner)) {
992
				$root = \OC\Files\Filesystem::getRoot();
993
			} else {
994
				$root = '';
995
			}
996
			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
997
			if (!isset($item)) {
998
				$where .= ' AND `file_target` IS NOT NULL ';
999
			}
1000
			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1001
			$fileDependent = true;
1002
			$queryArgs = array();
1003
		} else {
1004
			$fileDependent = false;
1005
			$root = '';
1006
			$collectionTypes = self::getCollectionItemTypes($itemType);
1007
			if ($includeCollections && !isset($item) && $collectionTypes) {
1008
				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1009
				if (!in_array($itemType, $collectionTypes)) {
1010
					$itemTypes = array_merge(array($itemType), $collectionTypes);
1011
				} else {
1012
					$itemTypes = $collectionTypes;
1013
				}
1014
				$placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
1015
				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
1016
				$queryArgs = $itemTypes;
1017
			} else {
1018
				$where = ' WHERE `item_type` = ?';
1019
				$queryArgs = array($itemType);
1020
			}
1021
		}
1022
		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1023
			$where .= ' AND `share_type` != ?';
1024
			$queryArgs[] = self::SHARE_TYPE_LINK;
1025
		}
1026
		if (isset($shareType)) {
1027
			// Include all user and group items
1028
			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1029
				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1030
				$queryArgs[] = self::SHARE_TYPE_USER;
1031
				$queryArgs[] = self::$shareTypeGroupUserUnique;
1032
				$queryArgs[] = $shareWith;
1033
1034
				$user = \OC::$server->getUserManager()->get($shareWith);
1035
				$groups = [];
1036
				if ($user) {
1037
					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1038
				}
1039
				if (!empty($groups)) {
1040
					$placeholders = implode(',', array_fill(0, count($groups), '?'));
1041
					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1042
					$queryArgs[] = self::SHARE_TYPE_GROUP;
1043
					$queryArgs = array_merge($queryArgs, $groups);
1044
				}
1045
				$where .= ')';
1046
				// Don't include own group shares
1047
				$where .= ' AND `uid_owner` != ?';
1048
				$queryArgs[] = $shareWith;
1049
			} else {
1050
				$where .= ' AND `share_type` = ?';
1051
				$queryArgs[] = $shareType;
1052
				if (isset($shareWith)) {
1053
					$where .= ' AND `share_with` = ?';
1054
					$queryArgs[] = $shareWith;
1055
				}
1056
			}
1057
		}
1058
		if (isset($uidOwner)) {
1059
			$where .= ' AND `uid_owner` = ?';
1060
			$queryArgs[] = $uidOwner;
1061
			if (!isset($shareType)) {
1062
				// Prevent unique user targets for group shares from being selected
1063
				$where .= ' AND `share_type` != ?';
1064
				$queryArgs[] = self::$shareTypeGroupUserUnique;
1065
			}
1066
			if ($fileDependent) {
1067
				$column = 'file_source';
1068
			} else {
1069
				$column = 'item_source';
1070
			}
1071
		} else {
1072
			if ($fileDependent) {
1073
				$column = 'file_target';
1074
			} else {
1075
				$column = 'item_target';
1076
			}
1077
		}
1078
		if (isset($item)) {
1079
			$collectionTypes = self::getCollectionItemTypes($itemType);
1080
			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1081
				$where .= ' AND (';
1082
			} else {
1083
				$where .= ' AND';
1084
			}
1085
			// If looking for own shared items, check item_source else check item_target
1086
			if (isset($uidOwner) || $itemShareWithBySource) {
1087
				// If item type is a file, file source needs to be checked in case the item was converted
1088
				if ($fileDependent) {
1089
					$where .= ' `file_source` = ?';
1090
					$column = 'file_source';
1091
				} else {
1092
					$where .= ' `item_source` = ?';
1093
					$column = 'item_source';
1094
				}
1095
			} else {
1096
				if ($fileDependent) {
1097
					$where .= ' `file_target` = ?';
1098
					$item = \OC\Files\Filesystem::normalizePath($item);
1099
				} else {
1100
					$where .= ' `item_target` = ?';
1101
				}
1102
			}
1103
			$queryArgs[] = $item;
1104
			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1105
				$placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
1106
				$where .= ' OR `item_type` IN ('.$placeholders.'))';
1107
				$queryArgs = array_merge($queryArgs, $collectionTypes);
1108
			}
1109
		}
1110
1111
		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1112
			// Make sure the unique user target is returned if it exists,
1113
			// unique targets should follow the group share in the database
1114
			// If the limit is not 1, the filtering can be done later
1115
			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1116
		} else {
1117
			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1118
		}
1119
1120
		if ($limit != -1 && !$includeCollections) {
1121
			// The limit must be at least 3, because filtering needs to be done
1122
			if ($limit < 3) {
1123
				$queryLimit = 3;
1124
			} else {
1125
				$queryLimit = $limit;
1126
			}
1127
		} else {
1128
			$queryLimit = null;
1129
		}
1130
		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1131
		$root = strlen($root);
1132
		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1133
		$result = $query->execute($queryArgs);
1134
		if ($result === false) {
1135
			\OCP\Util::writeLog('OCP\Share',
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1135
			/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share',

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...
1136
				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1137
				ILogger::ERROR);
1138
		}
1139
		$items = array();
1140
		$targets = array();
1141
		$switchedItems = array();
1142
		$mounts = array();
1143
		while ($row = $result->fetchRow()) {
1144
			self::transformDBResults($row);
1145
			// Filter out duplicate group shares for users with unique targets
1146
			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1147
				continue;
1148
			}
1149
			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1150
				$row['share_type'] = self::SHARE_TYPE_GROUP;
1151
				$row['unique_name'] = true; // remember that we use a unique name for this user
1152
				$row['share_with'] = $items[$row['parent']]['share_with'];
1153
				// if the group share was unshared from the user we keep the permission, otherwise
1154
				// we take the permission from the parent because this is always the up-to-date
1155
				// permission for the group share
1156
				if ($row['permissions'] > 0) {
1157
					$row['permissions'] = $items[$row['parent']]['permissions'];
1158
				}
1159
				// Remove the parent group share
1160
				unset($items[$row['parent']]);
1161
				if ($row['permissions'] == 0) {
1162
					continue;
1163
				}
1164
			} else if (!isset($uidOwner)) {
1165
				// Check if the same target already exists
1166
				if (isset($targets[$row['id']])) {
1167
					// Check if the same owner shared with the user twice
1168
					// through a group and user share - this is allowed
1169
					$id = $targets[$row['id']];
1170
					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1171
						// Switch to group share type to ensure resharing conditions aren't bypassed
1172
						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1173
							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1174
							$items[$id]['share_with'] = $row['share_with'];
1175
						}
1176
						// Switch ids if sharing permission is granted on only
1177
						// one share to ensure correct parent is used if resharing
1178
						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1179
							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1180
							$items[$row['id']] = $items[$id];
1181
							$switchedItems[$id] = $row['id'];
1182
							unset($items[$id]);
1183
							$id = $row['id'];
1184
						}
1185
						$items[$id]['permissions'] |= (int)$row['permissions'];
1186
1187
					}
1188
					continue;
1189
				} elseif (!empty($row['parent'])) {
1190
					$targets[$row['parent']] = $row['id'];
1191
				}
1192
			}
1193
			// Remove root from file source paths if retrieving own shared items
1194
			if (isset($uidOwner) && isset($row['path'])) {
1195
				if (isset($row['parent'])) {
1196
					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1197
					$parentResult = $query->execute(array($row['parent']));
1198
					if ($result === false) {
1199
						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1199
						/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .

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...
1200
							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1201
							ILogger::ERROR);
1202
					} else {
1203
						$parentRow = $parentResult->fetchRow();
1204
						$tmpPath = $parentRow['file_target'];
1205
						// find the right position where the row path continues from the target path
1206
						$pos = strrpos($row['path'], $parentRow['file_target']);
1207
						$subPath = substr($row['path'], $pos);
1208
						$splitPath = explode('/', $subPath);
1209
						foreach (array_slice($splitPath, 2) as $pathPart) {
1210
							$tmpPath = $tmpPath . '/' . $pathPart;
1211
						}
1212
						$row['path'] = $tmpPath;
1213
					}
1214
				} else {
1215
					if (!isset($mounts[$row['storage']])) {
1216
						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1217
						if (is_array($mountPoints) && !empty($mountPoints)) {
1218
							$mounts[$row['storage']] = current($mountPoints);
1219
						}
1220
					}
1221
					if (!empty($mounts[$row['storage']])) {
1222
						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1223
						$relPath = substr($path, $root); // path relative to data/user
1224
						$row['path'] = rtrim($relPath, '/');
1225
					}
1226
				}
1227
			}
1228
1229
			if($checkExpireDate) {
1230
				if (self::expireItem($row)) {
1231
					continue;
1232
				}
1233
			}
1234
			// Check if resharing is allowed, if not remove share permission
1235
			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
0 ignored issues
show
Bug introduced by
Are you sure you want to use the bitwise | or did you mean ||?
Loading history...
Deprecated Code introduced by
The function OCP\Util::isSharingDisabledForUser() has been deprecated: 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser ( Ignorable by Annotation )

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

1235
			if (isset($row['permissions']) && (!self::isResharingAllowed() | /** @scrutinizer ignore-deprecated */ \OCP\Util::isSharingDisabledForUser())) {

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...
1236
				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
1237
			}
1238
			// Add display names to result
1239
			$row['share_with_displayname'] = $row['share_with'];
1240
			if ( isset($row['share_with']) && $row['share_with'] != '' &&
1241
				$row['share_type'] === self::SHARE_TYPE_USER) {
1242
				$shareWithUser = \OC::$server->getUserManager()->get($row['share_with']);
1243
				$row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName();
1244
			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
1245
				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
1246
				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
1247
				foreach ($addressBookEntries as $entry) {
1248
					foreach ($entry['CLOUD'] as $cloudID) {
1249
						if ($cloudID === $row['share_with']) {
1250
							$row['share_with_displayname'] = $entry['FN'];
1251
						}
1252
					}
1253
				}
1254
			}
1255
			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
1256
				$ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']);
1257
				$row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName();
1258
			}
1259
1260
			if ($row['permissions'] > 0) {
1261
				$items[$row['id']] = $row;
1262
			}
1263
1264
		}
1265
1266
		// group items if we are looking for items shared with the current user
1267
		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\User::getUser() has been deprecated: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID() ( Ignorable by Annotation )

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

1267
		if (isset($shareWith) && $shareWith === /** @scrutinizer ignore-deprecated */ \OCP\User::getUser()) {

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...
1268
			$items = self::groupItems($items, $itemType);
1269
		}
1270
1271
		if (!empty($items)) {
1272
			$collectionItems = array();
1273
			foreach ($items as &$row) {
1274
				// Return only the item instead of a 2-dimensional array
1275
				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
1276
					if ($format == self::FORMAT_NONE) {
1277
						return $row;
1278
					} else {
1279
						break;
1280
					}
1281
				}
1282
				// Check if this is a collection of the requested item type
1283
				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
1284
					if (($collectionBackend = self::getBackend($row['item_type']))
1285
						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
1286
						// Collections can be inside collections, check if the item is a collection
1287
						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
1288
							$collectionItems[] = $row;
1289
						} else {
1290
							$collection = array();
1291
							$collection['item_type'] = $row['item_type'];
1292
							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1293
								$collection['path'] = basename($row['path']);
1294
							}
1295
							$row['collection'] = $collection;
1296
							// Fetch all of the children sources
1297
							$children = $collectionBackend->getChildren($row[$column]);
1298
							foreach ($children as $child) {
1299
								$childItem = $row;
1300
								$childItem['item_type'] = $itemType;
1301
								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
1302
									$childItem['item_source'] = $child['source'];
1303
									$childItem['item_target'] = $child['target'];
1304
								}
1305
								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1306
									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1307
										$childItem['file_source'] = $child['source'];
1308
									} else { // TODO is this really needed if we already know that we use the file backend?
1309
										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
1310
										$childItem['file_source'] = $meta['fileid'];
1311
									}
1312
									$childItem['file_target'] =
1313
										\OC\Files\Filesystem::normalizePath($child['file_path']);
1314
								}
1315
								if (isset($item)) {
1316
									if ($childItem[$column] == $item) {
1317
										// Return only the item instead of a 2-dimensional array
1318
										if ($limit == 1) {
1319
											if ($format == self::FORMAT_NONE) {
1320
												return $childItem;
1321
											} else {
1322
												// Unset the items array and break out of both loops
1323
												$items = array();
1324
												$items[] = $childItem;
1325
												break 2;
1326
											}
1327
										} else {
1328
											$collectionItems[] = $childItem;
1329
										}
1330
									}
1331
								} else {
1332
									$collectionItems[] = $childItem;
1333
								}
1334
							}
1335
						}
1336
					}
1337
					// Remove collection item
1338
					$toRemove = $row['id'];
1339
					if (array_key_exists($toRemove, $switchedItems)) {
1340
						$toRemove = $switchedItems[$toRemove];
1341
					}
1342
					unset($items[$toRemove]);
1343
				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
1344
					// FIXME: Thats a dirty hack to improve file sharing performance,
1345
					// see github issue #10588 for more details
1346
					// Need to find a solution which works for all back-ends
1347
					$collectionBackend = self::getBackend($row['item_type']);
1348
					$sharedParents = $collectionBackend->getParents($row['item_source']);
0 ignored issues
show
Bug introduced by
The method getParents() does not exist on OCP\Share_Backend. It seems like you code against a sub-type of OCP\Share_Backend such as OCA\Files_Sharing\ShareBackend\Folder or OCA\Files_Sharing\ShareBackend\Folder. ( Ignorable by Annotation )

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

1348
					/** @scrutinizer ignore-call */ 
1349
     $sharedParents = $collectionBackend->getParents($row['item_source']);
Loading history...
1349
					foreach ($sharedParents as $parent) {
1350
						$collectionItems[] = $parent;
1351
					}
1352
				}
1353
			}
1354
			if (!empty($collectionItems)) {
1355
				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
1356
				$items = array_merge($items, $collectionItems);
1357
			}
1358
1359
			// filter out invalid items, these can appear when subshare entries exist
1360
			// for a group in which the requested user isn't a member any more
1361
			$items = array_filter($items, function($item) {
1362
				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
1363
			});
1364
1365
			return self::formatResult($items, $column, $backend, $format, $parameters);
1366
		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
1367
			// FIXME: Thats a dirty hack to improve file sharing performance,
1368
			// see github issue #10588 for more details
1369
			// Need to find a solution which works for all back-ends
1370
			$collectionItems = array();
1371
			$collectionBackend = self::getBackend('folder');
1372
			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
1373
			foreach ($sharedParents as $parent) {
1374
				$collectionItems[] = $parent;
1375
			}
1376
			if ($limit === 1) {
1377
				return reset($collectionItems);
1378
			}
1379
			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
1380
		}
1381
1382
		return array();
1383
	}
1384
1385
	/**
1386
	 * group items with link to the same source
1387
	 *
1388
	 * @param array $items
1389
	 * @param string $itemType
1390
	 * @return array of grouped items
1391
	 */
1392
	protected static function groupItems($items, $itemType) {
1393
1394
		$fileSharing = $itemType === 'file' || $itemType === 'folder';
1395
1396
		$result = array();
1397
1398
		foreach ($items as $item) {
1399
			$grouped = false;
1400
			foreach ($result as $key => $r) {
1401
				// for file/folder shares we need to compare file_source, otherwise we compare item_source
1402
				// only group shares if they already point to the same target, otherwise the file where shared
1403
				// before grouping of shares was added. In this case we don't group them toi avoid confusions
1404
				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1405
					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1406
					// add the first item to the list of grouped shares
1407
					if (!isset($result[$key]['grouped'])) {
1408
						$result[$key]['grouped'][] = $result[$key];
1409
					}
1410
					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1411
					$result[$key]['grouped'][] = $item;
1412
					$grouped = true;
1413
					break;
1414
				}
1415
			}
1416
1417
			if (!$grouped) {
1418
				$result[] = $item;
1419
			}
1420
1421
		}
1422
1423
		return $result;
1424
	}
1425
1426
	/**
1427
	 * Put shared item into the database
1428
	 * @param string $itemType Item type
1429
	 * @param string $itemSource Item source
1430
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1431
	 * @param string $shareWith User or group the item is being shared with
1432
	 * @param string $uidOwner User that is the owner of shared item
1433
	 * @param int $permissions CRUDS permissions
1434
	 * @param boolean|array $parentFolder Parent folder target (optional)
1435
	 * @param string $token (optional)
1436
	 * @param string $itemSourceName name of the source item (optional)
1437
	 * @param \DateTime $expirationDate (optional)
1438
	 * @throws \Exception
1439
	 * @return mixed id of the new share or false
1440
	 */
1441
	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1442
								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
1443
1444
		$queriesToExecute = array();
1445
		$suggestedItemTarget = null;
1446
		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1447
		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1448
1449
		$result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
1450
		if(!empty($result)) {
1451
			$parent = $result['parent'];
1452
			$itemSource = $result['itemSource'];
1453
			$fileSource = $result['fileSource'];
1454
			$suggestedItemTarget = $result['suggestedItemTarget'];
1455
			$suggestedFileTarget = $result['suggestedFileTarget'];
1456
			$filePath = $result['filePath'];
1457
		}
1458
1459
		$isGroupShare = false;
1460
		if ($shareType == self::SHARE_TYPE_GROUP) {
1461
			$isGroupShare = true;
1462
			if (isset($shareWith['users'])) {
1463
				$users = $shareWith['users'];
1464
			} else {
1465
				$group = \OC::$server->getGroupManager()->get($shareWith['group']);
1466
				if ($group) {
0 ignored issues
show
introduced by
$group is of type OC\Group\Group, thus it always evaluated to true.
Loading history...
1467
					$users = $group->searchUsers('', -1, 0);
1468
					$userIds = [];
1469
					foreach ($users as $user) {
1470
						$userIds[] = $user->getUID();
1471
					}
1472
					$users = $userIds;
1473
				} else {
1474
					$users = [];
1475
				}
1476
			}
1477
			// remove current user from list
1478
			if (in_array(\OCP\User::getUser(), $users)) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\User::getUser() has been deprecated: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID() ( Ignorable by Annotation )

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

1478
			if (in_array(/** @scrutinizer ignore-deprecated */ \OCP\User::getUser(), $users)) {

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...
1479
				unset($users[array_search(\OCP\User::getUser(), $users)]);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\User::getUser() has been deprecated: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID() ( Ignorable by Annotation )

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

1479
				unset($users[array_search(/** @scrutinizer ignore-deprecated */ \OCP\User::getUser(), $users)]);

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...
1480
			}
1481
			$groupItemTarget = Helper::generateTarget($itemType, $itemSource,
1482
				$shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
1483
			$groupFileTarget = Helper::generateTarget($itemType, $itemSource,
1484
				$shareType, $shareWith['group'], $uidOwner, $filePath);
1485
1486
			// add group share to table and remember the id as parent
1487
			$queriesToExecute['groupShare'] = array(
1488
				'itemType'			=> $itemType,
1489
				'itemSource'		=> $itemSource,
1490
				'itemTarget'		=> $groupItemTarget,
1491
				'shareType'			=> $shareType,
1492
				'shareWith'			=> $shareWith['group'],
1493
				'uidOwner'			=> $uidOwner,
1494
				'permissions'		=> $permissions,
1495
				'shareTime'			=> time(),
1496
				'fileSource'		=> $fileSource,
1497
				'fileTarget'		=> $groupFileTarget,
1498
				'token'				=> $token,
1499
				'parent'			=> $parent,
1500
				'expiration'		=> $expirationDate,
1501
			);
1502
1503
		} else {
1504
			$users = array($shareWith);
1505
			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1506
				$suggestedItemTarget);
1507
		}
1508
1509
		$run = true;
1510
		$error = '';
1511
		$preHookData = array(
1512
			'itemType' => $itemType,
1513
			'itemSource' => $itemSource,
1514
			'shareType' => $shareType,
1515
			'uidOwner' => $uidOwner,
1516
			'permissions' => $permissions,
1517
			'fileSource' => $fileSource,
1518
			'expiration' => $expirationDate,
1519
			'token' => $token,
1520
			'run' => &$run,
1521
			'error' => &$error
1522
		);
1523
1524
		$preHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1525
		$preHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1526
1527
		\OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData);
1528
1529
		if ($run === false) {
0 ignored issues
show
introduced by
The condition $run === false is always false.
Loading history...
1530
			throw new \Exception($error);
1531
		}
1532
1533
		foreach ($users as $user) {
1534
			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1535
			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1536
1537
			$userShareType = $isGroupShare ? self::$shareTypeGroupUserUnique : $shareType;
1538
1539
			if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sourceExists of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1540
				$fileTarget = $sourceExists['file_target'];
1541
				$itemTarget = $sourceExists['item_target'];
1542
1543
				// for group shares we don't need a additional entry if the target is the same
1544
				if($isGroupShare && $groupItemTarget === $itemTarget) {
1545
					continue;
1546
				}
1547
1548
			} elseif(!$sourceExists && !$isGroupShare)  {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sourceExists of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1549
1550
				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1551
					$uidOwner, $suggestedItemTarget, $parent);
1552
				if (isset($fileSource)) {
1553
					if ($parentFolder) {
1554
						if ($parentFolder === true) {
1555
							$fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
1556
								$uidOwner, $suggestedFileTarget, $parent);
1557
							if ($fileTarget != $groupFileTarget) {
1558
								$parentFolders[$user]['folder'] = $fileTarget;
1559
							}
1560
						} else if (isset($parentFolder[$user])) {
1561
							$fileTarget = $parentFolder[$user]['folder'].$itemSource;
1562
							$parent = $parentFolder[$user]['id'];
1563
						}
1564
					} else {
1565
						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1566
							$user, $uidOwner, $suggestedFileTarget, $parent);
1567
					}
1568
				} else {
1569
					$fileTarget = null;
1570
				}
1571
1572
			} else {
1573
1574
				// group share which doesn't exists until now, check if we need a unique target for this user
1575
1576
				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1577
					$uidOwner, $suggestedItemTarget, $parent);
1578
1579
				// do we also need a file target
1580
				if (isset($fileSource)) {
1581
					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1582
						$uidOwner, $suggestedFileTarget, $parent);
1583
				} else {
1584
					$fileTarget = null;
1585
				}
1586
1587
				if (($itemTarget === $groupItemTarget) &&
1588
					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1589
					continue;
1590
				}
1591
			}
1592
1593
			$queriesToExecute[] = array(
1594
				'itemType'			=> $itemType,
1595
				'itemSource'		=> $itemSource,
1596
				'itemTarget'		=> $itemTarget,
1597
				'shareType'			=> $userShareType,
1598
				'shareWith'			=> $user,
1599
				'uidOwner'			=> $uidOwner,
1600
				'permissions'		=> $permissions,
1601
				'shareTime'			=> time(),
1602
				'fileSource'		=> $fileSource,
1603
				'fileTarget'		=> $fileTarget,
1604
				'token'				=> $token,
1605
				'parent'			=> $parent,
1606
				'expiration'		=> $expirationDate,
1607
			);
1608
1609
		}
1610
1611
		$id = false;
1612
		if ($isGroupShare) {
1613
			$id = self::insertShare($queriesToExecute['groupShare']);
1614
			// Save this id, any extra rows for this group share will need to reference it
1615
			$parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1616
			unset($queriesToExecute['groupShare']);
1617
		}
1618
1619
		foreach ($queriesToExecute as $shareQuery) {
1620
			$shareQuery['parent'] = $parent;
1621
			$id = self::insertShare($shareQuery);
1622
		}
1623
1624
		$postHookData = array(
1625
			'itemType' => $itemType,
1626
			'itemSource' => $itemSource,
1627
			'parent' => $parent,
1628
			'shareType' => $shareType,
1629
			'uidOwner' => $uidOwner,
1630
			'permissions' => $permissions,
1631
			'fileSource' => $fileSource,
1632
			'id' => $parent,
1633
			'token' => $token,
1634
			'expirationDate' => $expirationDate,
1635
		);
1636
1637
		$postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1638
		$postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1639
		$postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget;
1640
1641
		\OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData);
1642
1643
1644
		return $id ? $id : false;
1645
	}
1646
1647
	/**
1648
	 * @param string $itemType
1649
	 * @param string $itemSource
1650
	 * @param int $shareType
1651
	 * @param string $shareWith
1652
	 * @param string $uidOwner
1653
	 * @param int $permissions
1654
	 * @param string|null $itemSourceName
1655
	 * @param null|\DateTime $expirationDate
1656
	 */
1657
	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1658
		$backend = self::getBackend($itemType);
1659
1660
		$l = \OC::$server->getL10N('lib');
1661
		$result = array();
1662
1663
		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1664
1665
		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1666
		if ($checkReshare) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $checkReshare of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1667
			// Check if attempting to share back to owner
1668
			if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
1669
				$message = 'Sharing %1$s failed, because the user %2$s is the original sharer';
1670
				$message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
1671
1672
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1672
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);

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...
1673
				throw new \Exception($message_t);
1674
			}
1675
		}
1676
1677
		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1678
			// Check if share permissions is granted
1679
			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1680
				if (~(int)$checkReshare['permissions'] & $permissions) {
1681
					$message = 'Sharing %1$s failed, because the permissions exceed permissions granted to %2$s';
1682
					$message_t = $l->t('Sharing %1$s failed, because the permissions exceed permissions granted to %2$s', array($itemSourceName, $uidOwner));
1683
1684
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1684
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), ILogger::DEBUG);

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...
1685
					throw new \Exception($message_t);
1686
				} else {
1687
					// TODO Don't check if inside folder
1688
					$result['parent'] = $checkReshare['id'];
1689
1690
					$result['expirationDate'] = $expirationDate;
1691
					// $checkReshare['expiration'] could be null and then is always less than any value
1692
					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1693
						$result['expirationDate'] = $checkReshare['expiration'];
1694
					}
1695
1696
					// only suggest the same name as new target if it is a reshare of the
1697
					// same file/folder and not the reshare of a child
1698
					if ($checkReshare[$column] === $itemSource) {
1699
						$result['filePath'] = $checkReshare['file_target'];
1700
						$result['itemSource'] = $checkReshare['item_source'];
1701
						$result['fileSource'] = $checkReshare['file_source'];
1702
						$result['suggestedItemTarget'] = $checkReshare['item_target'];
1703
						$result['suggestedFileTarget'] = $checkReshare['file_target'];
1704
					} else {
1705
						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1706
						$result['suggestedItemTarget'] = null;
1707
						$result['suggestedFileTarget'] = null;
1708
						$result['itemSource'] = $itemSource;
1709
						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1710
					}
1711
				}
1712
			} else {
1713
				$message = 'Sharing %s failed, because resharing is not allowed';
1714
				$message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
1715
1716
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1716
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);

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...
1717
				throw new \Exception($message_t);
1718
			}
1719
		} else {
1720
			$result['parent'] = null;
1721
			$result['suggestedItemTarget'] = null;
1722
			$result['suggestedFileTarget'] = null;
1723
			$result['itemSource'] = $itemSource;
1724
			$result['expirationDate'] = $expirationDate;
1725
			if (!$backend->isValidSource($itemSource, $uidOwner)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $backend->isValidSource($itemSource, $uidOwner) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
1726
				$message = 'Sharing %1$s failed, because the sharing backend for '
1727
					.'%2$s could not find its source';
1728
				$message_t = $l->t('Sharing %1$s failed, because the sharing backend for %2$s could not find its source', array($itemSource, $itemType));
1729
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1729
				/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), ILogger::DEBUG);

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...
1730
				throw new \Exception($message_t);
1731
			}
1732
			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1733
				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1734
				if ($itemType == 'file' || $itemType == 'folder') {
1735
					$result['fileSource'] = $itemSource;
1736
				} else {
1737
					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
0 ignored issues
show
Bug introduced by
It seems like $result['filePath'] can also be of type false; however, parameter $path of OC\Files\Filesystem::getFileInfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1737
					$meta = \OC\Files\Filesystem::getFileInfo(/** @scrutinizer ignore-type */ $result['filePath']);
Loading history...
1738
					$result['fileSource'] = $meta['fileid'];
1739
				}
1740
				if ($result['fileSource'] == -1) {
1741
					$message = 'Sharing %s failed, because the file could not be found in the file cache';
1742
					$message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
1743
1744
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::writeLog() has been deprecated: 13.0.0 use log of \OCP\ILogger ( Ignorable by Annotation )

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

1744
					/** @scrutinizer ignore-deprecated */ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), ILogger::DEBUG);

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...
1745
					throw new \Exception($message_t);
1746
				}
1747
			} else {
1748
				$result['filePath'] = null;
1749
				$result['fileSource'] = null;
1750
			}
1751
		}
1752
1753
		return $result;
1754
	}
1755
1756
	/**
1757
	 *
1758
	 * @param array $shareData
1759
	 * @return mixed false in case of a failure or the id of the new share
1760
	 */
1761
	private static function insertShare(array $shareData) {
1762
1763
		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1764
			.' `item_type`, `item_source`, `item_target`, `share_type`,'
1765
			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1766
			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1767
		$query->bindValue(1, $shareData['itemType']);
1768
		$query->bindValue(2, $shareData['itemSource']);
1769
		$query->bindValue(3, $shareData['itemTarget']);
1770
		$query->bindValue(4, $shareData['shareType']);
1771
		$query->bindValue(5, $shareData['shareWith']);
1772
		$query->bindValue(6, $shareData['uidOwner']);
1773
		$query->bindValue(7, $shareData['permissions']);
1774
		$query->bindValue(8, $shareData['shareTime']);
1775
		$query->bindValue(9, $shareData['fileSource']);
1776
		$query->bindValue(10, $shareData['fileTarget']);
1777
		$query->bindValue(11, $shareData['token']);
1778
		$query->bindValue(12, $shareData['parent']);
1779
		$query->bindValue(13, $shareData['expiration'], 'datetime');
0 ignored issues
show
Bug introduced by
'datetime' of type string is incompatible with the type integer expected by parameter $type of OC_DB_StatementWrapper::bindValue(). ( Ignorable by Annotation )

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

1779
		$query->bindValue(13, $shareData['expiration'], /** @scrutinizer ignore-type */ 'datetime');
Loading history...
1780
		$result = $query->execute();
1781
1782
		$id = false;
1783
		if ($result) {
1784
			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1785
		}
1786
1787
		return $id;
1788
1789
	}
1790
1791
	/**
1792
	 * In case a password protected link is not yet authenticated this function will return false
1793
	 *
1794
	 * @param array $linkItem
1795
	 * @return boolean
1796
	 */
1797
	public static function checkPasswordProtectedShare(array $linkItem) {
1798
		if (!isset($linkItem['share_with'])) {
1799
			return true;
1800
		}
1801
		if (!isset($linkItem['share_type'])) {
1802
			return true;
1803
		}
1804
		if (!isset($linkItem['id'])) {
1805
			return true;
1806
		}
1807
1808
		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
1809
			return true;
1810
		}
1811
1812
		if ( \OC::$server->getSession()->exists('public_link_authenticated')
1813
			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
1814
			return true;
1815
		}
1816
1817
		return false;
1818
	}
1819
1820
	/**
1821
	 * construct select statement
1822
	 * @param int $format
1823
	 * @param boolean $fileDependent ist it a file/folder share or a generla share
1824
	 * @param string $uidOwner
1825
	 * @return string select statement
1826
	 */
1827
	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1828
		$select = '*';
1829
		if ($format == self::FORMAT_STATUSES) {
1830
			if ($fileDependent) {
1831
				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1832
					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1833
					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1834
					. '`uid_initiator`';
1835
			} else {
1836
				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1837
			}
1838
		} else {
1839
			if (isset($uidOwner)) {
1840
				if ($fileDependent) {
1841
					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1842
						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1843
						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1844
						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1845
				} else {
1846
					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1847
						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1848
				}
1849
			} else {
1850
				if ($fileDependent) {
1851
					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1852
						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1853
							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1854
							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1855
							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1856
					} else {
1857
						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1858
							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1859
							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1860
						    . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1861
							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1862
					}
1863
				}
1864
			}
1865
		}
1866
		return $select;
1867
	}
1868
1869
1870
	/**
1871
	 * transform db results
1872
	 * @param array $row result
1873
	 */
1874
	private static function transformDBResults(&$row) {
1875
		if (isset($row['id'])) {
1876
			$row['id'] = (int) $row['id'];
1877
		}
1878
		if (isset($row['share_type'])) {
1879
			$row['share_type'] = (int) $row['share_type'];
1880
		}
1881
		if (isset($row['parent'])) {
1882
			$row['parent'] = (int) $row['parent'];
1883
		}
1884
		if (isset($row['file_parent'])) {
1885
			$row['file_parent'] = (int) $row['file_parent'];
1886
		}
1887
		if (isset($row['file_source'])) {
1888
			$row['file_source'] = (int) $row['file_source'];
1889
		}
1890
		if (isset($row['permissions'])) {
1891
			$row['permissions'] = (int) $row['permissions'];
1892
		}
1893
		if (isset($row['storage'])) {
1894
			$row['storage'] = (int) $row['storage'];
1895
		}
1896
		if (isset($row['stime'])) {
1897
			$row['stime'] = (int) $row['stime'];
1898
		}
1899
		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1900
			// discard expiration date for non-link shares, which might have been
1901
			// set by ancient bugs
1902
			$row['expiration'] = null;
1903
		}
1904
	}
1905
1906
	/**
1907
	 * format result
1908
	 * @param array $items result
1909
	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1910
	 * @param \OCP\Share_Backend $backend sharing backend
1911
	 * @param int $format
1912
	 * @param array $parameters additional format parameters
1913
	 * @return array format result
1914
	 */
1915
	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1916
		if ($format === self::FORMAT_NONE) {
1917
			return $items;
1918
		} else if ($format === self::FORMAT_STATUSES) {
1919
			$statuses = array();
1920
			foreach ($items as $item) {
1921
				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1922
					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1923
						continue;
1924
					}
1925
					$statuses[$item[$column]]['link'] = true;
1926
				} else if (!isset($statuses[$item[$column]])) {
1927
					$statuses[$item[$column]]['link'] = false;
1928
				}
1929
				if (!empty($item['file_target'])) {
1930
					$statuses[$item[$column]]['path'] = $item['path'];
1931
				}
1932
			}
1933
			return $statuses;
1934
		} else {
1935
			return $backend->formatItems($items, $format, $parameters);
1936
		}
1937
	}
1938
1939
	/**
1940
	 * remove protocol from URL
1941
	 *
1942
	 * @param string $url
1943
	 * @return string
1944
	 */
1945
	public static function removeProtocolFromUrl($url) {
1946
		if (strpos($url, 'https://') === 0) {
1947
			return substr($url, strlen('https://'));
1948
		} else if (strpos($url, 'http://') === 0) {
1949
			return substr($url, strlen('http://'));
1950
		}
1951
1952
		return $url;
1953
	}
1954
1955
	/**
1956
	 * try http post first with https and then with http as a fallback
1957
	 *
1958
	 * @param string $remoteDomain
1959
	 * @param string $urlSuffix
1960
	 * @param array $fields post parameters
1961
	 * @return array
1962
	 */
1963
	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1964
		$protocol = 'https://';
1965
		$result = [
1966
			'success' => false,
1967
			'result' => '',
1968
		];
1969
		$try = 0;
1970
		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1971
		while ($result['success'] === false && $try < 2) {
1972
			$federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
0 ignored issues
show
Bug introduced by
The method discover() does not exist on stdClass. ( Ignorable by Annotation )

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

1972
			/** @scrutinizer ignore-call */ 
1973
   $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1973
			$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1974
			$client = \OC::$server->getHTTPClientService()->newClient();
1975
1976
			try {
1977
				$response = $client->post(
1978
					$protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
1979
					[
1980
						'body' => $fields,
1981
						'connect_timeout' => 10,
1982
					]
1983
				);
1984
1985
				$result = ['success' => true, 'result' => $response->getBody()];
1986
			} catch (\Exception $e) {
1987
				$result = ['success' => false, 'result' => $e->getMessage()];
1988
			}
1989
1990
			$try++;
1991
			$protocol = 'http://';
1992
		}
1993
1994
		return $result;
1995
	}
1996
1997
	/**
1998
	 * send server-to-server share to remote server
1999
	 *
2000
	 * @param string $token
2001
	 * @param string $shareWith
2002
	 * @param string $name
2003
	 * @param int $remote_id
2004
	 * @param string $owner
2005
	 * @return bool
2006
	 */
2007
	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2008
2009
		list($user, $remote) = Helper::splitUserRemote($shareWith);
2010
2011
		if ($user && $remote) {
2012
			$url = $remote;
2013
2014
			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2015
2016
			$fields = array(
2017
				'shareWith' => $user,
2018
				'token' => $token,
2019
				'name' => $name,
2020
				'remoteId' => $remote_id,
2021
				'owner' => $owner,
2022
				'remote' => $local,
2023
			);
2024
2025
			$url = self::removeProtocolFromUrl($url);
2026
			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2027
			$status = json_decode($result['result'], true);
2028
2029
			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2030
				\OC_Hook::emit(\OCP\Share::class, 'federated_share_added', ['server' => $remote]);
2031
				return true;
2032
			}
2033
2034
		}
2035
2036
		return false;
2037
	}
2038
2039
	/**
2040
	 * send server-to-server unshare to remote server
2041
	 *
2042
	 * @param string $remote url
2043
	 * @param int $id share id
2044
	 * @param string $token
2045
	 * @return bool
2046
	 */
2047
	private static function sendRemoteUnshare($remote, $id, $token) {
2048
		$url = rtrim($remote, '/');
2049
		$fields = array('token' => $token, 'format' => 'json');
2050
		$url = self::removeProtocolFromUrl($url);
2051
		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2052
		$status = json_decode($result['result'], true);
2053
2054
		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2055
	}
2056
2057
	/**
2058
	 * @return bool
2059
	 */
2060
	public static function isDefaultExpireDateEnabled() {
2061
		$defaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
2062
		return $defaultExpireDateEnabled === 'yes';
2063
	}
2064
2065
	/**
2066
	 * @return int
2067
	 */
2068
	public static function getExpireInterval() {
2069
		return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
2070
	}
2071
2072
	/**
2073
	 * Checks whether the given path is reachable for the given owner
2074
	 *
2075
	 * @param string $path path relative to files
2076
	 * @param string $ownerStorageId storage id of the owner
2077
	 *
2078
	 * @return boolean true if file is reachable, false otherwise
2079
	 */
2080
	private static function isFileReachable($path, $ownerStorageId) {
2081
		// if outside the home storage, file is always considered reachable
2082
		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2083
			substr($ownerStorageId, 0, 13) === 'object::user:'
2084
		)) {
2085
			return true;
2086
		}
2087
2088
		// if inside the home storage, the file has to be under "/files/"
2089
		$path = ltrim($path, '/');
2090
		if (substr($path, 0, 6) === 'files/') {
2091
			return true;
2092
		}
2093
2094
		return false;
2095
	}
2096
2097
	/**
2098
	 * @param string $password
2099
	 * @throws \Exception
2100
	 */
2101
	private static function verifyPassword($password) {
2102
2103
		$accepted = true;
2104
		$message = '';
2105
		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2106
			'password' => $password,
2107
			'accepted' => &$accepted,
2108
			'message' => &$message
2109
		]);
2110
2111
		if (!$accepted) {
0 ignored issues
show
introduced by
The condition $accepted is always true.
Loading history...
2112
			throw new \Exception($message);
2113
		}
2114
	}
2115
}
2116