Completed
Push — master ( c38f87...350aa8 )
by Lukas
27s
created

Share::getShareByToken()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 21
Code Lines 13

Duplication

Lines 3
Ratio 14.29 %

Importance

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

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

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

Loading history...
123
			return true;
124
		}
125
		return false;
126
	}
127
128
	/**
129
	 * Find which users can access a shared item
130
	 * @param string $path to the file
131
	 * @param string $ownerUser owner of the file
132
	 * @param IUserManager $userManager
133
	 * @param ILogger $logger
134
	 * @param boolean $includeOwner include owner to the list of users with access to the file
135
	 * @param boolean $returnUserPaths Return an array with the user => path map
136
	 * @param boolean $recursive take all parent folders into account (default true)
137
	 * @return array
138
	 * @note $path needs to be relative to user data dir, e.g. 'file.txt'
139
	 *       not '/admin/data/file.txt'
140
	 * @throws \OC\User\NoUserException
141
	 */
142
	public static function getUsersSharingFile($path,
143
											   $ownerUser,
144
											   IUserManager $userManager,
145
											   ILogger $logger,
146
											   $includeOwner = false,
147
											   $returnUserPaths = false,
148
											   $recursive = true) {
149
		$userObject = $userManager->get($ownerUser);
150
151 View Code Duplication
		if (is_null($userObject)) {
152
			$logger->error(
153
				sprintf(
154
					'Backends provided no user object for %s',
155
					$ownerUser
156
				),
157
				[
158
					'app' => 'files',
159
				]
160
			);
161
			throw new \OC\User\NoUserException('Backends provided no user object');
162
		}
163
164
		$ownerUser = $userObject->getUID();
165
166
		Filesystem::initMountPoints($ownerUser);
167
		$shares = $sharePaths = $fileTargets = array();
168
		$publicShare = false;
169
		$remoteShare = false;
170
		$source = -1;
171
		$cache = $mountPath = false;
172
173
		$view = new \OC\Files\View('/' . $ownerUser . '/files');
174
		$meta = $view->getFileInfo($path);
175
		if ($meta) {
176
			$path = substr($meta->getPath(), strlen('/' . $ownerUser . '/files'));
177
		} else {
178
			// if the file doesn't exists yet we start with the parent folder
179
			$meta = $view->getFileInfo(dirname($path));
180
		}
181
182
		if($meta !== false) {
183
			$source = $meta['fileid'];
184
			$cache = new \OC\Files\Cache\Cache($meta['storage']);
185
186
			$mountPath = $meta->getMountPoint()->getMountPoint();
187
			if ($mountPath !== false) {
188
				$mountPath = substr($mountPath, strlen('/' . $ownerUser . '/files'));
189
			}
190
		}
191
192
		$paths = [];
193
		while ($source !== -1) {
194
			// Fetch all shares with another user
195
			if (!$returnUserPaths) {
196
				$query = \OC_DB::prepare(
197
					'SELECT `share_with`, `file_source`, `file_target`
198
					FROM
199
					`*PREFIX*share`
200
					WHERE
201
					`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
202
				);
203
				$result = $query->execute(array($source, self::SHARE_TYPE_USER));
204
			} else {
205
				$query = \OC_DB::prepare(
206
					'SELECT `share_with`, `file_source`, `file_target`
207
				FROM
208
				`*PREFIX*share`
209
				WHERE
210
				`item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')'
211
				);
212
				$result = $query->execute(array($source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
213
			}
214
215
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

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

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

Loading history...
216
				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
217
			} else {
218
				while ($row = $result->fetchRow()) {
219
					$shares[] = $row['share_with'];
220
					if ($returnUserPaths) {
221
						$fileTargets[(int) $row['file_source']][$row['share_with']] = $row;
222
					}
223
				}
224
			}
225
226
			// We also need to take group shares into account
227
			$query = \OC_DB::prepare(
228
				'SELECT `share_with`, `file_source`, `file_target`
229
				FROM
230
				`*PREFIX*share`
231
				WHERE
232
				`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
233
			);
234
235
			$result = $query->execute(array($source, self::SHARE_TYPE_GROUP));
236
237
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

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

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

Loading history...
238
				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
239
			} else {
240
				$groupManager = \OC::$server->getGroupManager();
241
				while ($row = $result->fetchRow()) {
242
243
					$usersInGroup = [];
244
					$group = $groupManager->get($row['share_with']);
245 View Code Duplication
					if ($group) {
246
						$users = $group->searchUsers('', -1, 0);
247
						$userIds = array();
248
						foreach ($users as $user) {
249
							$userIds[] = $user->getUID();
250
						}
251
						$usersInGroup = $userIds;
252
					}
253
					$shares = array_merge($shares, $usersInGroup);
254
					if ($returnUserPaths) {
255
						foreach ($usersInGroup as $user) {
256
							if (!isset($fileTargets[(int) $row['file_source']][$user])) {
257
								// When the user already has an entry for this file source
258
								// the file is either shared directly with him as well, or
259
								// he has an exception entry (because of naming conflict).
260
								$fileTargets[(int) $row['file_source']][$user] = $row;
261
							}
262
						}
263
					}
264
				}
265
			}
266
267
			//check for public link shares
268 View Code Duplication
			if (!$publicShare) {
269
				$query = \OC_DB::prepare('
270
					SELECT `share_with`
271
					FROM `*PREFIX*share`
272
					WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
273
				);
274
275
				$result = $query->execute(array($source, self::SHARE_TYPE_LINK));
276
277
				if (\OCP\DB::isError($result)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

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

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

Loading history...
278
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
279
				} else {
280
					if ($result->fetchRow()) {
281
						$publicShare = true;
282
					}
283
				}
284
			}
285
286
			//check for remote share
287 View Code Duplication
			if (!$remoteShare) {
288
				$query = \OC_DB::prepare('
289
					SELECT `share_with`
290
					FROM `*PREFIX*share`
291
					WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
292
				);
293
294
				$result = $query->execute(array($source, self::SHARE_TYPE_REMOTE));
295
296
				if (\OCP\DB::isError($result)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

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

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

Loading history...
297
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
298
				} else {
299
					if ($result->fetchRow()) {
300
						$remoteShare = true;
301
					}
302
				}
303
			}
304
305
			// let's get the parent for the next round
306
			$meta = $cache->get((int)$source);
307
			if ($recursive === true && $meta !== false) {
308
				$paths[$source] = $meta['path'];
309
				$source = (int)$meta['parent'];
310
			} else {
311
				$source = -1;
312
			}
313
		}
314
315
		// Include owner in list of users, if requested
316
		if ($includeOwner) {
317
			$shares[] = $ownerUser;
318
		}
319
320
		if ($returnUserPaths) {
321
			$fileTargetIDs = array_keys($fileTargets);
322
			$fileTargetIDs = array_unique($fileTargetIDs);
323
324
			if (!empty($fileTargetIDs)) {
325
				$query = \OC_DB::prepare(
326
					'SELECT `fileid`, `path`
327
					FROM `*PREFIX*filecache`
328
					WHERE `fileid` IN (' . implode(',', $fileTargetIDs) . ')'
329
				);
330
				$result = $query->execute();
331
332
				if (\OCP\DB::isError($result)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

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

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

Loading history...
333
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
334
				} else {
335
					while ($row = $result->fetchRow()) {
336
						foreach ($fileTargets[$row['fileid']] as $uid => $shareData) {
337
							if ($mountPath !== false) {
338
								$sharedPath = $shareData['file_target'];
339
								$sharedPath .= substr($path, strlen($mountPath) + strlen($paths[$row['fileid']]));
340
								$sharePaths[$uid] = $sharedPath;
341
							} else {
342
								$sharedPath = $shareData['file_target'];
343
								$sharedPath .= substr($path, strlen($row['path']) -5);
344
								$sharePaths[$uid] = $sharedPath;
345
							}
346
						}
347
					}
348
				}
349
			}
350
351
			if ($includeOwner) {
352
				$sharePaths[$ownerUser] = $path;
353
			} else {
354
				unset($sharePaths[$ownerUser]);
355
			}
356
357
			return $sharePaths;
358
		}
359
360
		return array('users' => array_unique($shares), 'public' => $publicShare, 'remote' => $remoteShare);
361
	}
362
363
	/**
364
	 * Get the items of item type shared with the current user
365
	 * @param string $itemType
366
	 * @param int $format (optional) Format type must be defined by the backend
367
	 * @param mixed $parameters (optional)
368
	 * @param int $limit Number of items to return (optional) Returns all by default
369
	 * @param boolean $includeCollections (optional)
370
	 * @return mixed Return depends on format
371
	 */
372
	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
373
											  $parameters = null, $limit = -1, $includeCollections = false) {
374
		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
375
			$parameters, $limit, $includeCollections);
376
	}
377
378
	/**
379
	 * Get the items of item type shared with a user
380
	 * @param string $itemType
381
	 * @param string $user id for which user we want the shares
382
	 * @param int $format (optional) Format type must be defined by the backend
383
	 * @param mixed $parameters (optional)
384
	 * @param int $limit Number of items to return (optional) Returns all by default
385
	 * @param boolean $includeCollections (optional)
386
	 * @return mixed Return depends on format
387
	 */
388
	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
389
												  $parameters = null, $limit = -1, $includeCollections = false) {
390
		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
391
			$parameters, $limit, $includeCollections);
392
	}
393
394
	/**
395
	 * Get the item of item type shared with the current user
396
	 * @param string $itemType
397
	 * @param string $itemTarget
398
	 * @param int $format (optional) Format type must be defined by the backend
399
	 * @param mixed $parameters (optional)
400
	 * @param boolean $includeCollections (optional)
401
	 * @return mixed Return depends on format
402
	 */
403
	public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
404
											 $parameters = null, $includeCollections = false) {
405
		return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
406
			$parameters, 1, $includeCollections);
407
	}
408
409
	/**
410
	 * Get the item of item type shared with a given user by source
411
	 * @param string $itemType
412
	 * @param string $itemSource
413
	 * @param string $user User to whom the item was shared
414
	 * @param string $owner Owner of the share
415
	 * @param int $shareType only look for a specific share type
416
	 * @return array Return list of items with file_target, permissions and expiration
417
	 */
418
	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
419
		$shares = array();
420
		$fileDependent = false;
421
422
		$where = 'WHERE';
423
		$fileDependentWhere = '';
424
		if ($itemType === 'file' || $itemType === 'folder') {
425
			$fileDependent = true;
426
			$column = 'file_source';
427
			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
428
			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
429
		} else {
430
			$column = 'item_source';
431
		}
432
433
		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
434
435
		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
436
		$arguments = array($itemSource, $itemType);
437
		// for link shares $user === null
438
		if ($user !== null) {
439
			$where .= ' AND `share_with` = ? ';
440
			$arguments[] = $user;
441
		}
442
443
		if ($shareType !== null) {
444
			$where .= ' AND `share_type` = ? ';
445
			$arguments[] = $shareType;
446
		}
447
448
		if ($owner !== null) {
449
			$where .= ' AND `uid_owner` = ? ';
450
			$arguments[] = $owner;
451
		}
452
453
		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
454
455
		$result = \OC_DB::executeAudited($query, $arguments);
456
457
		while ($row = $result->fetchRow()) {
458
			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
459
				continue;
460
			}
461
			if ($fileDependent && (int)$row['file_parent'] === -1) {
462
				// if it is a mount point we need to get the path from the mount manager
463
				$mountManager = \OC\Files\Filesystem::getMountManager();
464
				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
465
				if (!empty($mountPoint)) {
466
					$path = $mountPoint[0]->getMountPoint();
467
					$path = trim($path, '/');
468
					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
469
					$row['path'] = $path;
470
				} else {
471
					\OC::$server->getLogger()->warning(
472
						'Could not resolve mount point for ' . $row['storage_id'],
473
						['app' => 'OCP\Share']
474
					);
475
				}
476
			}
477
			$shares[] = $row;
478
		}
479
480
		//if didn't found a result than let's look for a group share.
481
		if(empty($shares) && $user !== null) {
482
			$userObject = \OC::$server->getUserManager()->get($user);
483
			$groups = [];
484
			if ($userObject) {
485
				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
486
			}
487
488
			if (!empty($groups)) {
489
				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
490
				$arguments = array($itemSource, $itemType, $groups);
491
				$types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
492
493
				if ($owner !== null) {
494
					$where .= ' AND `uid_owner` = ?';
495
					$arguments[] = $owner;
496
					$types[] = null;
497
				}
498
499
				// TODO: inject connection, hopefully one day in the future when this
500
				// class isn't static anymore...
501
				$conn = \OC::$server->getDatabaseConnection();
502
				$result = $conn->executeQuery(
503
					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
504
					$arguments,
0 ignored issues
show
Documentation introduced by
$arguments is of type array<integer,string|array>, but the function expects a array<integer,string>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
505
					$types
506
				);
507
508
				while ($row = $result->fetch()) {
509
					$shares[] = $row;
510
				}
511
			}
512
		}
513
514
		return $shares;
515
516
	}
517
518
	/**
519
	 * Get the item of item type shared with the current user by source
520
	 * @param string $itemType
521
	 * @param string $itemSource
522
	 * @param int $format (optional) Format type must be defined by the backend
523
	 * @param mixed $parameters
524
	 * @param boolean $includeCollections
525
	 * @param string $shareWith (optional) define against which user should be checked, default: current user
526
	 * @return array
527
	 */
528
	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
529
													 $parameters = null, $includeCollections = false, $shareWith = null) {
530
		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
531
		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
532
			$parameters, 1, $includeCollections, true);
533
	}
534
535
	/**
536
	 * Get the item of item type shared by a link
537
	 * @param string $itemType
538
	 * @param string $itemSource
539
	 * @param string $uidOwner Owner of link
540
	 * @return array
541
	 */
542
	public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
543
		return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE,
544
			null, 1);
545
	}
546
547
	/**
548
	 * Based on the given token the share information will be returned - password protected shares will be verified
549
	 * @param string $token
550
	 * @param bool $checkPasswordProtection
551
	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
552
	 */
553
	public static function getShareByToken($token, $checkPasswordProtection = true) {
554
		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
555
		$result = $query->execute(array($token));
556 View Code Duplication
		if ($result === false) {
557
			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
558
		}
559
		$row = $result->fetchRow();
560
		if ($row === false) {
561
			return false;
562
		}
563
		if (is_array($row) and self::expireItem($row)) {
564
			return false;
565
		}
566
567
		// password protected shares need to be authenticated
568
		if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) {
569
			return false;
570
		}
571
572
		return $row;
573
	}
574
575
	/**
576
	 * resolves reshares down to the last real share
577
	 * @param array $linkItem
578
	 * @return array file owner
579
	 */
580
	public static function resolveReShare($linkItem)
581
	{
582
		if (isset($linkItem['parent'])) {
583
			$parent = $linkItem['parent'];
584 View Code Duplication
			while (isset($parent)) {
585
				$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
586
				$item = $query->execute(array($parent))->fetchRow();
587
				if (isset($item['parent'])) {
588
					$parent = $item['parent'];
589
				} else {
590
					return $item;
591
				}
592
			}
593
		}
594
		return $linkItem;
595
	}
596
597
598
	/**
599
	 * Get the shared items of item type owned by the current user
600
	 * @param string $itemType
601
	 * @param int $format (optional) Format type must be defined by the backend
602
	 * @param mixed $parameters
603
	 * @param int $limit Number of items to return (optional) Returns all by default
604
	 * @param boolean $includeCollections
605
	 * @return mixed Return depends on format
606
	 */
607
	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
608
										  $limit = -1, $includeCollections = false) {
609
		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
610
			$parameters, $limit, $includeCollections);
611
	}
612
613
	/**
614
	 * Get the shared item of item type owned by the current user
615
	 * @param string $itemType
616
	 * @param string $itemSource
617
	 * @param int $format (optional) Format type must be defined by the backend
618
	 * @param mixed $parameters
619
	 * @param boolean $includeCollections
620
	 * @return mixed Return depends on format
621
	 */
622
	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
623
										 $parameters = null, $includeCollections = false) {
624
		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
625
			$parameters, -1, $includeCollections);
626
	}
627
628
	/**
629
	 * Get all users an item is shared with
630
	 * @param string $itemType
631
	 * @param string $itemSource
632
	 * @param string $uidOwner
633
	 * @param boolean $includeCollections
634
	 * @param boolean $checkExpireDate
635
	 * @return array Return array of users
636
	 */
637
	public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) {
638
639
		$users = array();
640
		$items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate);
641
		if ($items) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $items 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...
642
			foreach ($items as $item) {
643
				if ((int)$item['share_type'] === self::SHARE_TYPE_USER) {
644
					$users[] = $item['share_with'];
645
				} else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
646
647
					$group = \OC::$server->getGroupManager()->get($item['share_with']);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $group is correct as \OC::$server->getGroupMa...et($item['share_with']) (which targets OC\Group\Manager::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
648
					$userIds = [];
649 View Code Duplication
					if ($group) {
650
						$users = $group->searchUsers('', -1, 0);
651
						foreach ($users as $user) {
652
							$userIds[] = $user->getUID();
653
						}
654
						return $userIds;
655
					}
656
657
					$users = array_merge($users, $userIds);
658
				}
659
			}
660
		}
661
		return $users;
662
	}
663
664
	/**
665
	 * Share an item with a user, group, or via private link
666
	 * @param string $itemType
667
	 * @param string $itemSource
668
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
669
	 * @param string $shareWith User or group the item is being shared with
670
	 * @param int $permissions CRUDS
671
	 * @param string $itemSourceName
672
	 * @param \DateTime $expirationDate
673
	 * @param bool $passwordChanged
674
	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
675
	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
676
	 * @throws \Exception
677
	 */
678
	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
679
680
		$backend = self::getBackend($itemType);
681
		$l = \OC::$server->getL10N('lib');
682
683
		if ($backend->isShareTypeAllowed($shareType) === false) {
684
			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
685
			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
686
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
687
			throw new \Exception($message_t);
688
		}
689
690
		$uidOwner = \OC_User::getUser();
691
		$shareWithinGroupOnly = self::shareWithGroupMembersOnly();
692
693
		if (is_null($itemSourceName)) {
694
			$itemSourceName = $itemSource;
695
		}
696
		$itemName = $itemSourceName;
697
698
		// check if file can be shared
699
		if ($itemType === 'file' or $itemType === 'folder') {
700
			$path = \OC\Files\Filesystem::getPath($itemSource);
701
			$itemName = $path;
702
703
			// verify that the file exists before we try to share it
704 View Code Duplication
			if (!$path) {
705
				$message = 'Sharing %s failed, because the file does not exist';
706
				$message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
707
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
708
				throw new \Exception($message_t);
709
			}
710
			// verify that the user has share permission
711 View Code Duplication
			if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Util::isSharingDisabledForUser() has been deprecated with message: 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser

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

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

Loading history...
712
				$message = 'You are not allowed to share %s';
713
				$message_t = $l->t('You are not allowed to share %s', [$path]);
714
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
715
				throw new \Exception($message_t);
716
			}
717
		}
718
719
		//verify that we don't share a folder which already contains a share mount point
720
		if ($itemType === 'folder') {
721
			$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
722
			$mountManager = \OC\Files\Filesystem::getMountManager();
723
			$mounts = $mountManager->findIn($path);
724
			foreach ($mounts as $mount) {
725
				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
726
					$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
727
					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
728
					throw new \Exception($message);
729
				}
730
731
			}
732
		}
733
734
		// single file shares should never have delete permissions
735
		if ($itemType === 'file') {
736
			$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
737
		}
738
739
		//Validate expirationDate
740
		if ($expirationDate !== null) {
741
			try {
742
				/*
743
				 * Reuse the validateExpireDate.
744
				 * We have to pass time() since the second arg is the time
745
				 * the file was shared, since it is not shared yet we just use
746
				 * the current time.
747
				 */
748
				$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
749
			} catch (\Exception $e) {
750
				throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
751
			}
752
		}
753
754
		// Verify share type and sharing conditions are met
755
		if ($shareType === self::SHARE_TYPE_USER) {
756 View Code Duplication
			if ($shareWith == $uidOwner) {
757
				$message = 'Sharing %s failed, because you can not share with yourself';
758
				$message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
759
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
760
				throw new \Exception($message_t);
761
			}
762 View Code Duplication
			if (!\OC_User::userExists($shareWith)) {
763
				$message = 'Sharing %s failed, because the user %s does not exist';
764
				$message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
765
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
766
				throw new \Exception($message_t);
767
			}
768
			if ($shareWithinGroupOnly) {
769
				$userManager = \OC::$server->getUserManager();
770
				$groupManager = \OC::$server->getGroupManager();
771
				$userOwner = $userManager->get($uidOwner);
772
				$userShareWith = $userManager->get($shareWith);
773
				$groupsOwner = [];
774
				$groupsShareWith = [];
775
				if ($userOwner) {
776
					$groupsOwner = $groupManager->getUserGroupIds($userOwner);
777
				}
778
				if ($userShareWith) {
779
					$groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
780
				}
781
				$inGroup = array_intersect($groupsOwner, $groupsShareWith);
782 View Code Duplication
				if (empty($inGroup)) {
783
					$message = 'Sharing %s failed, because the user '
784
						.'%s is not a member of any groups that %s is a member of';
785
					$message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
786
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
787
					throw new \Exception($message_t);
788
				}
789
			}
790
			// Check if the item source is already shared with the user, either from the same owner or a different user
791 View Code Duplication
			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
792
				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
793
				// Only allow the same share to occur again if it is the same
794
				// owner and is not a user share, this use case is for increasing
795
				// permissions for a specific user
796
				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
797
					$message = 'Sharing %s failed, because this item is already shared with %s';
798
					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
799
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
800
					throw new \Exception($message_t);
801
				}
802
			}
803 View Code Duplication
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
804
				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
805
				// Only allow the same share to occur again if it is the same
806
				// owner and is not a user share, this use case is for increasing
807
				// permissions for a specific user
808
				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
809
					$message = 'Sharing %s failed, because this item is already shared with user %s';
810
					$message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
811
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
812
					throw new \Exception($message_t);
813
				}
814
			}
815
		} else if ($shareType === self::SHARE_TYPE_GROUP) {
816
			if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
817
				$message = 'Sharing %s failed, because the group %s does not exist';
818
				$message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
819
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
820
				throw new \Exception($message_t);
821
			}
822
			if ($shareWithinGroupOnly && !\OC_Group::inGroup($uidOwner, $shareWith)) {
823
				$group = \OC::$server->getGroupManager()->get($shareWith);
824
				$user = \OC::$server->getUserManager()->get($uidOwner);
825
				if (!$group || !$user || !$group->inGroup($user)) {
826
					$message = 'Sharing %s failed, because '
827
						. '%s is not a member of the group %s';
828
					$message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
829
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
830
					throw new \Exception($message_t);
831
				}
832
			}
833
			// Check if the item source is already shared with the group, either from the same owner or a different user
834
			// The check for each user in the group is done inside the put() function
835
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
836
				null, self::FORMAT_NONE, null, 1, true, true)) {
837
838
				if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
839
					$message = 'Sharing %s failed, because this item is already shared with %s';
840
					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
841
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
842
					throw new \Exception($message_t);
843
				}
844
			}
845
			// Convert share with into an array with the keys group and users
846
			$group = $shareWith;
847
			$shareWith = array();
848
			$shareWith['group'] = $group;
849
850
851
			$groupObject = \OC::$server->getGroupManager()->get($group);
852
			$userIds = [];
853 View Code Duplication
			if ($groupObject) {
854
				$users = $groupObject->searchUsers('', -1, 0);
855
				foreach ($users as $user) {
856
					$userIds[] = $user->getUID();
857
				}
858
			}
859
860
			$shareWith['users'] = array_diff($userIds, array($uidOwner));
861
		} else if ($shareType === self::SHARE_TYPE_LINK) {
862
			$updateExistingShare = false;
863
			if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
864
865
				// IF the password is changed via the old ajax endpoint verify it before deleting the old share
866
				if ($passwordChanged === true) {
867
					self::verifyPassword($shareWith);
868
				}
869
870
				// when updating a link share
871
				// FIXME Don't delete link if we update it
872
				if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
873
					$uidOwner, self::FORMAT_NONE, null, 1)) {
874
					// remember old token
875
					$oldToken = $checkExists['token'];
876
					$oldPermissions = $checkExists['permissions'];
877
					//delete the old share
878
					Helper::delete($checkExists['id']);
879
					$updateExistingShare = true;
880
				}
881
882
				if ($passwordChanged === null) {
883
					// Generate hash of password - same method as user passwords
884
					if (is_string($shareWith) && $shareWith !== '') {
885
						self::verifyPassword($shareWith);
886
						$shareWith = \OC::$server->getHasher()->hash($shareWith);
887
					} else {
888
						// reuse the already set password, but only if we change permissions
889
						// otherwise the user disabled the password protection
890
						if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
0 ignored issues
show
Bug introduced by
The variable $oldPermissions does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
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...
891
							$shareWith = $checkExists['share_with'];
892
						}
893
					}
894
				} else {
895
					if ($passwordChanged === true) {
896
						if (is_string($shareWith) && $shareWith !== '') {
897
							self::verifyPassword($shareWith);
898
							$shareWith = \OC::$server->getHasher()->hash($shareWith);
899
						}
900
					} else if ($updateExistingShare) {
901
						$shareWith = $checkExists['share_with'];
902
					}
903
				}
904
905 View Code Duplication
				if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
906
					$message = 'You need to provide a password to create a public link, only protected links are allowed';
907
					$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
908
					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
909
					throw new \Exception($message_t);
910
				}
911
912
				if ($updateExistingShare === false &&
913
					self::isDefaultExpireDateEnabled() &&
914
					empty($expirationDate)) {
915
					$expirationDate = Helper::calcExpireDate();
916
				}
917
918
				// Generate token
919
				if (isset($oldToken)) {
920
					$token = $oldToken;
921
				} else {
922
					$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
923
						\OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_UPPER.
924
						\OCP\Security\ISecureRandom::CHAR_DIGITS
925
					);
926
				}
927
				$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
928
					null, $token, $itemSourceName, $expirationDate);
929
				if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null 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...
930
					return $token;
931
				} else {
932
					return false;
933
				}
934
			}
935
			$message = 'Sharing %s failed, because sharing with links is not allowed';
936
			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
937
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
938
			throw new \Exception($message_t);
939
		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
940
941
			/*
942
			 * Check if file is not already shared with the remote user
943
			 */
944
			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
0 ignored issues
show
Unused Code introduced by
$checkExists is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
945
				$shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
946
					$message = 'Sharing %s failed, because this item is already shared with %s';
947
					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
948
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
949
					throw new \Exception($message_t);
950
			}
951
952
			// don't allow federated shares if source and target server are the same
953
			list($user, $remote) = Helper::splitUserRemote($shareWith);
954
			$currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
955
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
956
			if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
957
				$message = 'Not allowed to create a federated share with the same user.';
958
				$message_t = $l->t('Not allowed to create a federated share with the same user');
959
				\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
960
				throw new \Exception($message_t);
961
			}
962
963
			$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
964
				\OCP\Security\ISecureRandom::CHAR_DIGITS);
965
966
			$shareWith = $user . '@' . $remote;
967
			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
968
969
			$send = false;
970
			if ($shareId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shareId of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null 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...
971
				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
972
			}
973
974
			if ($send === false) {
975
				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
976
				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
977
				$message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
978
				throw new \Exception($message_t);
979
			}
980
981
			return $send;
982 View Code Duplication
		} else {
983
			// Future share types need to include their own conditions
984
			$message = 'Share type %s is not valid for %s';
985
			$message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
986
			\OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
987
			throw new \Exception($message_t);
988
		}
989
990
		// Put the item into the database
991
		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
0 ignored issues
show
Bug introduced by
It seems like $shareWith defined by array() on line 847 can also be of type array<string,?,{"users":"array"}>; however, OC\Share\Share::put() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
992
993
		return $result ? true : false;
994
	}
995
996
	/**
997
	 * Unshare an item from a user, group, or delete a private link
998
	 * @param string $itemType
999
	 * @param string $itemSource
1000
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1001
	 * @param string $shareWith User or group the item is being shared with
1002
	 * @param string $owner owner of the share, if null the current user is used
1003
	 * @return boolean true on success or false on failure
1004
	 */
1005
	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
1006
1007
		// check if it is a valid itemType
1008
		self::getBackend($itemType);
1009
1010
		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
1011
1012
		$toDelete = array();
1013
		$newParent = null;
1014
		$currentUser = $owner ? $owner : \OC_User::getUser();
1015
		foreach ($items as $item) {
1016
			// delete the item with the expected share_type and owner
1017
			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
1018
				$toDelete = $item;
1019
				// if there is more then one result we don't have to delete the children
1020
				// but update their parent. For group shares the new parent should always be
1021
				// the original group share and not the db entry with the unique name
1022
			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
1023
				$newParent = $item['parent'];
1024
			} else {
1025
				$newParent = $item['id'];
1026
			}
1027
		}
1028
1029
		if (!empty($toDelete)) {
1030
			self::unshareItem($toDelete, $newParent);
1031
			return true;
1032
		}
1033
		return false;
1034
	}
1035
1036
	/**
1037
	 * Unshare an item from all users, groups, and remove all links
1038
	 * @param string $itemType
1039
	 * @param string $itemSource
1040
	 * @return boolean true on success or false on failure
1041
	 */
1042
	public static function unshareAll($itemType, $itemSource) {
1043
		// Get all of the owners of shares of this item.
1044
		$query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' );
1045
		$result = $query->execute(array($itemType, $itemSource));
1046
		$shares = array();
1047
		// Add each owner's shares to the array of all shares for this item.
1048
		while ($row = $result->fetchRow()) {
1049
			$shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner']));
1050
		}
1051
		if (!empty($shares)) {
1052
			// Pass all the vars we have for now, they may be useful
1053
			$hookParams = array(
1054
				'itemType' => $itemType,
1055
				'itemSource' => $itemSource,
1056
				'shares' => $shares,
1057
			);
1058
			\OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams);
1059
			foreach ($shares as $share) {
1060
				self::unshareItem($share);
1061
			}
1062
			\OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams);
1063
			return true;
1064
		}
1065
		return false;
1066
	}
1067
1068
	/**
1069
	 * Unshare an item shared with the current user
1070
	 * @param string $itemType
1071
	 * @param string $itemOrigin Item target or source
1072
	 * @param boolean $originIsSource true if $itemOrigin is the source, false if $itemOrigin is the target (optional)
1073
	 * @return boolean true on success or false on failure
1074
	 *
1075
	 * Unsharing from self is not allowed for items inside collections
1076
	 */
1077
	public static function unshareFromSelf($itemType, $itemOrigin, $originIsSource = false) {
1078
		$originType = ($originIsSource) ? 'source' : 'target';
1079
		$uid = \OCP\User::getUser();
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getUser() has been deprecated with message: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID()

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

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

Loading history...
1080
1081
		if ($itemType === 'file' || $itemType === 'folder') {
1082
			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `file_' . $originType . '` = ?';
1083
		} else {
1084
			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `item_' . $originType . '` = ?';
1085
		}
1086
1087
		$query = \OCP\DB::prepare($statement);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

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

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

Loading history...
1088
		$result = $query->execute(array($itemType, $itemOrigin));
1089
1090
		$shares = $result->fetchAll();
1091
1092
		$listOfUnsharedItems = array();
1093
1094
		$itemUnshared = false;
1095
		foreach ($shares as $share) {
1096
			if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
1097
				$share['share_with'] === $uid) {
1098
				$deletedShares = Helper::delete($share['id']);
1099
				$shareTmp = array(
1100
					'id' => $share['id'],
1101
					'shareWith' => $share['share_with'],
1102
					'itemTarget' => $share['item_target'],
1103
					'itemType' => $share['item_type'],
1104
					'shareType' => (int)$share['share_type'],
1105
				);
1106
				if (isset($share['file_target'])) {
1107
					$shareTmp['fileTarget'] = $share['file_target'];
1108
				}
1109
				$listOfUnsharedItems = array_merge($listOfUnsharedItems, $deletedShares, array($shareTmp));
1110
				$itemUnshared = true;
1111
				break;
1112
			} elseif ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
1113
				$group = \OC::$server->getGroupManager()->get($share['share_with']);
1114
				$user = \OC::$server->getUserManager()->get($uid);
1115
				if ($group && $user && $group->inGroup($user)) {
1116
					$groupShare = $share;
1117
				}
1118
			} elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
1119
				$share['share_with'] === $uid) {
1120
				$uniqueGroupShare = $share;
1121
			}
1122
		}
1123
1124
		if (!$itemUnshared && isset($groupShare) && !isset($uniqueGroupShare)) {
1125
			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
1126
				.' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
1127
				.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
1128
				.' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
1129
			$query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
1130
				$groupShare['id'], self::$shareTypeGroupUserUnique,
1131
				\OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
1132
				$groupShare['file_target']));
1133
			$shareTmp = array(
1134
				'id' => $groupShare['id'],
1135
				'shareWith' => $groupShare['share_with'],
1136
				'itemTarget' => $groupShare['item_target'],
1137
				'itemType' => $groupShare['item_type'],
1138
				'shareType' => (int)$groupShare['share_type'],
1139
			);
1140
			if (isset($groupShare['file_target'])) {
1141
				$shareTmp['fileTarget'] = $groupShare['file_target'];
1142
			}
1143
			$listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1144
			$itemUnshared = true;
1145
		} elseif (!$itemUnshared && isset($uniqueGroupShare)) {
1146
			$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
1147
			$query->execute(array(0, $uniqueGroupShare['id']));
1148
			$shareTmp = array(
1149
				'id' => $uniqueGroupShare['id'],
1150
				'shareWith' => $uniqueGroupShare['share_with'],
1151
				'itemTarget' => $uniqueGroupShare['item_target'],
1152
				'itemType' => $uniqueGroupShare['item_type'],
1153
				'shareType' => (int)$uniqueGroupShare['share_type'],
1154
			);
1155
			if (isset($uniqueGroupShare['file_target'])) {
1156
				$shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
1157
			}
1158
			$listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1159
			$itemUnshared = true;
1160
		}
1161
1162
		if ($itemUnshared) {
1163
			\OC_Hook::emit('OCP\Share', 'post_unshareFromSelf',
1164
				array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
1165
		}
1166
1167
		return $itemUnshared;
1168
	}
1169
1170
	/**
1171
	 * sent status if users got informed by mail about share
1172
	 * @param string $itemType
1173
	 * @param string $itemSource
1174
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1175
	 * @param string $recipient with whom was the file shared
1176
	 * @param boolean $status
1177
	 */
1178
	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
1179
		$status = $status ? 1 : 0;
1180
1181
		$query = \OC_DB::prepare(
1182
			'UPDATE `*PREFIX*share`
1183
					SET `mail_send` = ?
1184
					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
1185
1186
		$result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
1187
1188
		if($result === false) {
1189
			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
1190
		}
1191
	}
1192
1193
	/**
1194
	 * Set the permissions of an item for a specific user or group
1195
	 * @param string $itemType
1196
	 * @param string $itemSource
1197
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1198
	 * @param string $shareWith User or group the item is being shared with
1199
	 * @param int $permissions CRUDS permissions
1200
	 * @return boolean true on success or false on failure
1201
	 * @throws \Exception when trying to grant more permissions then the user has himself
1202
	 */
1203
	public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
1204
		$l = \OC::$server->getL10N('lib');
1205
		$connection = \OC::$server->getDatabaseConnection();
1206
1207
		$intArrayToLiteralArray = function($intArray, $eb) {
1208
			return array_map(function($int) use ($eb) {
1209
				return $eb->literal((int)$int, 'integer');
1210
			}, $intArray);
1211
		};
1212
		$sanitizeItem = function($item) {
1213
			$item['id'] = (int)$item['id'];
1214
			$item['premissions'] = (int)$item['permissions'];
1215
			return $item;
1216
		};
1217
1218
		if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
1219
			\OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
1220
			// Check if this item is a reshare and verify that the permissions
1221
			// granted don't exceed the parent shared item
1222
			if (isset($rootItem['parent'])) {
1223
				$qb = $connection->getQueryBuilder();
1224
				$qb->select('permissions')
1225
					->from('share')
1226
					->where($qb->expr()->eq('id', $qb->createParameter('id')))
1227
					->setParameter(':id', $rootItem['parent']);
1228
				$dbresult = $qb->execute();
1229
1230
				$result = $dbresult->fetch();
1231
				$dbresult->closeCursor();
1232
				if (~(int)$result['permissions'] & $permissions) {
1233
					$message = 'Setting permissions for %s failed,'
1234
						.' because the permissions exceed permissions granted to %s';
1235
					$message_t = $l->t('Setting permissions for %s failed, because the permissions exceed permissions granted to %s', array($itemSource, \OC_User::getUser()));
1236
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, \OC_User::getUser()), \OCP\Util::DEBUG);
1237
					throw new \Exception($message_t);
1238
				}
1239
			}
1240
			$qb = $connection->getQueryBuilder();
1241
			$qb->update('share')
1242
				->set('permissions', $qb->createParameter('permissions'))
1243
				->where($qb->expr()->eq('id', $qb->createParameter('id')))
1244
				->setParameter(':id', $rootItem['id'])
1245
				->setParameter(':permissions', $permissions);
1246
			$qb->execute();
1247
			if ($itemType === 'file' || $itemType === 'folder') {
1248
				\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
1249
					'itemType' => $itemType,
1250
					'itemSource' => $itemSource,
1251
					'shareType' => $shareType,
1252
					'shareWith' => $shareWith,
1253
					'uidOwner' => \OC_User::getUser(),
1254
					'permissions' => $permissions,
1255
					'path' => $rootItem['path'],
1256
					'share' => $rootItem
1257
				));
1258
			}
1259
1260
			// Share id's to update with the new permissions
1261
			$ids = [];
1262
			$items = [];
1263
1264
			// Check if permissions were removed
1265
			if ((int)$rootItem['permissions'] & ~$permissions) {
1266
				// If share permission is removed all reshares must be deleted
1267
				if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
1268
					// delete all shares, keep parent and group children
1269
					Helper::delete($rootItem['id'], true, null, null, true);
1270
				}
1271
1272
				// Remove permission from all children
1273
				$parents = [$rootItem['id']];
1274
				while (!empty($parents)) {
1275
					$parents = $intArrayToLiteralArray($parents, $qb->expr());
1276
					$qb = $connection->getQueryBuilder();
1277
					$qb->select('id', 'permissions', 'item_type')
1278
						->from('share')
1279
						->where($qb->expr()->in('parent', $parents));
1280
					$result = $qb->execute();
1281
					// Reset parents array, only go through loop again if
1282
					// items are found that need permissions removed
1283
					$parents = [];
1284
					while ($item = $result->fetch()) {
1285
						$item = $sanitizeItem($item);
1286
1287
						$items[] = $item;
1288
						// Check if permissions need to be removed
1289
						if ($item['permissions'] & ~$permissions) {
1290
							// Add to list of items that need permissions removed
1291
							$ids[] = $item['id'];
1292
							$parents[] = $item['id'];
1293
						}
1294
					}
1295
					$result->closeCursor();
1296
				}
1297
1298
				// Remove the permissions for all reshares of this item
1299
				if (!empty($ids)) {
1300
					$ids = "'".implode("','", $ids)."'";
1301
					// TODO this should be done with Doctrine platform objects
1302
					if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
1303
						$andOp = 'BITAND(`permissions`, ?)';
1304
					} else {
1305
						$andOp = '`permissions` & ?';
1306
					}
1307
					$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
1308
						.' WHERE `id` IN ('.$ids.')');
1309
					$query->execute(array($permissions));
1310
				}
1311
1312
			}
1313
1314
			/*
1315
			 * Permissions were added
1316
			 * Update all USERGROUP shares. (So group shares where the user moved their mountpoint).
1317
			 */
1318
			if ($permissions & ~(int)$rootItem['permissions']) {
1319
				$qb = $connection->getQueryBuilder();
1320
				$qb->select('id', 'permissions', 'item_type')
1321
					->from('share')
1322
					->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
1323
					->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
1324
					->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
1325
					->setParameter(':parent', (int)$rootItem['id'])
1326
					->setParameter(':share_type', 2)
1327
					->setParameter(':shareDeleted', 0);
1328
				$result = $qb->execute();
1329
1330
				$ids = [];
1331
				while ($item = $result->fetch()) {
1332
					$item = $sanitizeItem($item);
1333
					$items[] = $item;
1334
					$ids[] = $item['id'];
1335
				}
1336
				$result->closeCursor();
1337
1338
				// Add permssions for all USERGROUP shares of this item
1339
				if (!empty($ids)) {
1340
					$ids = $intArrayToLiteralArray($ids, $qb->expr());
1341
1342
					$qb = $connection->getQueryBuilder();
1343
					$qb->update('share')
1344
						->set('permissions', $qb->createParameter('permissions'))
1345
						->where($qb->expr()->in('id', $ids))
1346
						->setParameter(':permissions', $permissions);
1347
					$qb->execute();
1348
				}
1349
			}
1350
1351
			foreach ($items as $item) {
1352
				\OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
1353
			}
1354
1355
			return true;
1356
		}
1357
		$message = 'Setting permissions for %s failed, because the item was not found';
1358
		$message_t = $l->t('Setting permissions for %s failed, because the item was not found', array($itemSource));
1359
1360
		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
1361
		throw new \Exception($message_t);
1362
	}
1363
1364
	/**
1365
	 * validate expiration date if it meets all constraints
1366
	 *
1367
	 * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
1368
	 * @param string $shareTime timestamp when the file was shared
1369
	 * @param string $itemType
1370
	 * @param string $itemSource
1371
	 * @return \DateTime validated date
1372
	 * @throws \Exception when the expire date is in the past or further in the future then the enforced date
1373
	 */
1374
	private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
1375
		$l = \OC::$server->getL10N('lib');
1376
		$date = new \DateTime($expireDate);
1377
		$today = new \DateTime('now');
1378
1379
		// if the user doesn't provide a share time we need to get it from the database
1380
		// fall-back mode to keep API stable, because the $shareTime parameter was added later
1381
		$defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
1382
		if ($defaultExpireDateEnforced && $shareTime === null) {
1383
			$items = self::getItemShared($itemType, $itemSource);
1384
			$firstItem = reset($items);
1385
			$shareTime = (int)$firstItem['stime'];
1386
		}
1387
1388
		if ($defaultExpireDateEnforced) {
1389
			// initialize max date with share time
1390
			$maxDate = new \DateTime();
1391
			$maxDate->setTimestamp($shareTime);
1392
			$maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
1393
			$maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
1394
			if ($date > $maxDate) {
1395
				$warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
1396
				$warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
1397
				\OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1398
				throw new \Exception($warning_t);
1399
			}
1400
		}
1401
1402 View Code Duplication
		if ($date < $today) {
1403
			$message = 'Cannot set expiration date. Expiration date is in the past';
1404
			$message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
1405
			\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
1406
			throw new \Exception($message_t);
1407
		}
1408
1409
		return $date;
1410
	}
1411
1412
	/**
1413
	 * Set expiration date for a share
1414
	 * @param string $itemType
1415
	 * @param string $itemSource
1416
	 * @param string $date expiration date
1417
	 * @param int $shareTime timestamp from when the file was shared
1418
	 * @return boolean
1419
	 * @throws \Exception when the expire date is not set, in the past or further in the future then the enforced date
1420
	 */
1421
	public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
1422
		$user = \OC_User::getUser();
1423
		$l = \OC::$server->getL10N('lib');
1424
1425
		if ($date == '') {
1426 View Code Duplication
			if (\OCP\Util::isDefaultExpireDateEnforced()) {
1427
				$warning = 'Cannot clear expiration date. Shares are required to have an expiration date.';
1428
				$warning_t = $l->t('Cannot clear expiration date. Shares are required to have an expiration date.');
1429
				\OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1430
				throw new \Exception($warning_t);
1431
			} else {
1432
				$date = null;
1433
			}
1434
		} else {
1435
			$date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource);
1436
		}
1437
		$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ?  AND `uid_owner` = ? AND `share_type` = ?');
1438
		$query->bindValue(1, $date, 'datetime');
1439
		$query->bindValue(2, $itemType);
1440
		$query->bindValue(3, $itemSource);
1441
		$query->bindValue(4, $user);
1442
		$query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
1443
1444
		$query->execute();
1445
1446
		\OC_Hook::emit('OCP\Share', 'post_set_expiration_date', array(
1447
			'itemType' => $itemType,
1448
			'itemSource' => $itemSource,
1449
			'date' => $date,
1450
			'uidOwner' => $user
1451
		));
1452
1453
		return true;
1454
	}
1455
1456
	/**
1457
	 * Retrieve the owner of a connection
1458
	 *
1459
	 * @param IDBConnection $connection
1460
	 * @param int $shareId
1461
	 * @throws \Exception
1462
	 * @return string uid of share owner
1463
	 */
1464
	private static function getShareOwner(IDBConnection $connection, $shareId) {
1465
		$qb = $connection->getQueryBuilder();
1466
1467
		$qb->select('uid_owner')
1468
			->from('share')
1469
			->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1470
			->setParameter(':shareId', $shareId);
1471
		$result = $qb->execute();
1472
		$result = $result->fetch();
1473
1474
		if (empty($result)) {
1475
			throw new \Exception('Share not found');
1476
		}
1477
1478
		return $result['uid_owner'];
1479
	}
1480
1481
	/**
1482
	 * Set password for a public link share
1483
	 *
1484
	 * @param IUserSession $userSession
1485
	 * @param IDBConnection $connection
1486
	 * @param IConfig $config
1487
	 * @param int $shareId
1488
	 * @param string $password
1489
	 * @throws \Exception
1490
	 * @return boolean
1491
	 */
1492
	public static function setPassword(IUserSession $userSession,
1493
	                                   IDBConnection $connection,
1494
	                                   IConfig $config,
1495
	                                   $shareId, $password) {
1496
		$user = $userSession->getUser();
1497
		if (is_null($user)) {
1498
			throw new \Exception("User not logged in");
1499
		}
1500
1501
		$uid = self::getShareOwner($connection, $shareId);
1502
1503
		if ($uid !== $user->getUID()) {
1504
			throw new \Exception('Cannot update share of a different user');
1505
		}
1506
1507
		if ($password === '') {
1508
			$password = null;
1509
		}
1510
1511
		//If passwords are enforced the password can't be null
1512
		if (self::enforcePassword($config) && is_null($password)) {
1513
			throw new \Exception('Cannot remove password');
1514
		}
1515
1516
		self::verifyPassword($password);
1517
1518
		$qb = $connection->getQueryBuilder();
1519
		$qb->update('share')
1520
			->set('share_with', $qb->createParameter('pass'))
1521
			->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1522
			->setParameter(':pass', is_null($password) ? null : \OC::$server->getHasher()->hash($password))
1523
			->setParameter(':shareId', $shareId);
1524
1525
		$qb->execute();
1526
1527
		return true;
1528
	}
1529
1530
	/**
1531
	 * Checks whether a share has expired, calls unshareItem() if yes.
1532
	 * @param array $item Share data (usually database row)
1533
	 * @return boolean True if item was expired, false otherwise.
1534
	 */
1535
	protected static function expireItem(array $item) {
1536
1537
		$result = false;
1538
1539
		// only use default expiration date for link shares
1540
		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
1541
1542
			// calculate expiration date
1543
			if (!empty($item['expiration'])) {
1544
				$userDefinedExpire = new \DateTime($item['expiration']);
1545
				$expires = $userDefinedExpire->getTimestamp();
1546
			} else {
1547
				$expires = null;
1548
			}
1549
1550
1551
			// get default expiration settings
1552
			$defaultSettings = Helper::getDefaultExpireSetting();
1553
			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
1554
1555
1556
			if (is_int($expires)) {
1557
				$now = time();
1558
				if ($now > $expires) {
1559
					self::unshareItem($item);
1560
					$result = true;
1561
				}
1562
			}
1563
		}
1564
		return $result;
1565
	}
1566
1567
	/**
1568
	 * Unshares a share given a share data array
1569
	 * @param array $item Share data (usually database row)
1570
	 * @param int $newParent parent ID
1571
	 * @return null
1572
	 */
1573
	protected static function unshareItem(array $item, $newParent = null) {
1574
1575
		$shareType = (int)$item['share_type'];
1576
		$shareWith = null;
1577
		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
1578
			$shareWith = $item['share_with'];
1579
		}
1580
1581
		// Pass all the vars we have for now, they may be useful
1582
		$hookParams = array(
1583
			'id'            => $item['id'],
1584
			'itemType'      => $item['item_type'],
1585
			'itemSource'    => $item['item_source'],
1586
			'shareType'     => $shareType,
1587
			'shareWith'     => $shareWith,
1588
			'itemParent'    => $item['parent'],
1589
			'uidOwner'      => $item['uid_owner'],
1590
		);
1591
		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
1592
			$hookParams['fileSource'] = $item['file_source'];
1593
			$hookParams['fileTarget'] = $item['file_target'];
1594
		}
1595
1596
		\OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
1597
		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
1598
		$deletedShares[] = $hookParams;
1599
		$hookParams['deletedShares'] = $deletedShares;
1600
		\OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
1601
		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
1602
			list(, $remote) = Helper::splitUserRemote($item['share_with']);
1603
			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
1604
		}
1605
	}
1606
1607
	/**
1608
	 * Get the backend class for the specified item type
1609
	 * @param string $itemType
1610
	 * @throws \Exception
1611
	 * @return \OCP\Share_Backend
1612
	 */
1613
	public static function getBackend($itemType) {
1614
		$l = \OC::$server->getL10N('lib');
1615
		if (isset(self::$backends[$itemType])) {
1616
			return self::$backends[$itemType];
1617
		} else if (isset(self::$backendTypes[$itemType]['class'])) {
1618
			$class = self::$backendTypes[$itemType]['class'];
1619
			if (class_exists($class)) {
1620
				self::$backends[$itemType] = new $class;
1621 View Code Duplication
				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
1622
					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
1623
					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
1624
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1625
					throw new \Exception($message_t);
1626
				}
1627
				return self::$backends[$itemType];
1628 View Code Duplication
			} else {
1629
				$message = 'Sharing backend %s not found';
1630
				$message_t = $l->t('Sharing backend %s not found', array($class));
1631
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1632
				throw new \Exception($message_t);
1633
			}
1634
		}
1635
		$message = 'Sharing backend for %s not found';
1636
		$message_t = $l->t('Sharing backend for %s not found', array($itemType));
1637
		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
1638
		throw new \Exception($message_t);
1639
	}
1640
1641
	/**
1642
	 * Check if resharing is allowed
1643
	 * @return boolean true if allowed or false
1644
	 *
1645
	 * Resharing is allowed by default if not configured
1646
	 */
1647
	public static function isResharingAllowed() {
1648
		if (!isset(self::$isResharingAllowed)) {
1649
			if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
1650
				self::$isResharingAllowed = true;
1651
			} else {
1652
				self::$isResharingAllowed = false;
1653
			}
1654
		}
1655
		return self::$isResharingAllowed;
1656
	}
1657
1658
	/**
1659
	 * Get a list of collection item types for the specified item type
1660
	 * @param string $itemType
1661
	 * @return array
1662
	 */
1663
	private static function getCollectionItemTypes($itemType) {
1664
		$collectionTypes = array($itemType);
1665
		foreach (self::$backendTypes as $type => $backend) {
1666
			if (in_array($backend['collectionOf'], $collectionTypes)) {
1667
				$collectionTypes[] = $type;
1668
			}
1669
		}
1670
		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
1671
		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
1672
			unset($collectionTypes[0]);
1673
		}
1674
		// Return array if collections were found or the item type is a
1675
		// collection itself - collections can be inside collections
1676
		if (count($collectionTypes) > 0) {
1677
			return $collectionTypes;
1678
		}
1679
		return false;
1680
	}
1681
1682
	/**
1683
	 * Get the owners of items shared with a user.
1684
	 *
1685
	 * @param string $user The user the items are shared with.
1686
	 * @param string $type The type of the items shared with the user.
1687
	 * @param boolean $includeCollections Include collection item types (optional)
1688
	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
1689
	 * @return array
1690
	 */
1691
	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
1692
		// First, we find out if $type is part of a collection (and if that collection is part of
1693
		// another one and so on).
1694
		$collectionTypes = array();
1695
		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
1696
			$collectionTypes[] = $type;
1697
		}
1698
1699
		// Of these collection types, along with our original $type, we make a
1700
		// list of the ones for which a sharing backend has been registered.
1701
		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
1702
		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
1703
		$allMaybeSharedItems = array();
1704
		foreach ($collectionTypes as $collectionType) {
0 ignored issues
show
Bug introduced by
The expression $collectionTypes of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1705
			if (isset(self::$backends[$collectionType])) {
1706
				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
1707
					$collectionType,
1708
					$user,
1709
					self::FORMAT_NONE
1710
				);
1711
			}
1712
		}
1713
1714
		$owners = array();
1715
		if ($includeOwner) {
1716
			$owners[] = $user;
1717
		}
1718
1719
		// We take a look at all shared items of the given $type (or of the collections it is part of)
1720
		// and find out their owners. Then, we gather the tags for the original $type from all owners,
1721
		// and return them as elements of a list that look like "Tag (owner)".
1722
		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
1723
			foreach ($maybeSharedItems as $sharedItem) {
1724
				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
1725
					$owners[] = $sharedItem['uid_owner'];
1726
				}
1727
			}
1728
		}
1729
1730
		return $owners;
1731
	}
1732
1733
	/**
1734
	 * Get shared items from the database
1735
	 * @param string $itemType
1736
	 * @param string $item Item source or target (optional)
1737
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
1738
	 * @param string $shareWith User or group the item is being shared with
1739
	 * @param string $uidOwner User that is the owner of shared items (optional)
1740
	 * @param int $format Format to convert items to with formatItems() (optional)
1741
	 * @param mixed $parameters to pass to formatItems() (optional)
1742
	 * @param int $limit Number of items to return, -1 to return all matches (optional)
1743
	 * @param boolean $includeCollections Include collection item types (optional)
1744
	 * @param boolean $itemShareWithBySource (optional)
1745
	 * @param boolean $checkExpireDate
1746
	 * @return array
1747
	 *
1748
	 * See public functions getItem(s)... for parameter usage
1749
	 *
1750
	 */
1751
	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
1752
									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
1753
									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
1754
		if (!self::isEnabled()) {
1755
			return array();
1756
		}
1757
		$backend = self::getBackend($itemType);
1758
		$collectionTypes = false;
1759
		// Get filesystem root to add it to the file target and remove from the
1760
		// file source, match file_source with the file cache
1761
		if ($itemType == 'file' || $itemType == 'folder') {
1762
			if(!is_null($uidOwner)) {
1763
				$root = \OC\Files\Filesystem::getRoot();
1764
			} else {
1765
				$root = '';
1766
			}
1767
			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
1768
			if (!isset($item)) {
1769
				$where .= ' AND `file_target` IS NOT NULL ';
1770
			}
1771
			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1772
			$fileDependent = true;
1773
			$queryArgs = array();
1774
		} else {
1775
			$fileDependent = false;
1776
			$root = '';
1777
			$collectionTypes = self::getCollectionItemTypes($itemType);
1778
			if ($includeCollections && !isset($item) && $collectionTypes) {
1779
				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1780
				if (!in_array($itemType, $collectionTypes)) {
1781
					$itemTypes = array_merge(array($itemType), $collectionTypes);
1782
				} else {
1783
					$itemTypes = $collectionTypes;
1784
				}
1785
				$placeholders = join(',', array_fill(0, count($itemTypes), '?'));
1786
				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
1787
				$queryArgs = $itemTypes;
1788
			} else {
1789
				$where = ' WHERE `item_type` = ?';
1790
				$queryArgs = array($itemType);
1791
			}
1792
		}
1793
		if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
1794
			$where .= ' AND `share_type` != ?';
1795
			$queryArgs[] = self::SHARE_TYPE_LINK;
1796
		}
1797
		if (isset($shareType)) {
1798
			// Include all user and group items
1799
			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1800
				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1801
				$queryArgs[] = self::SHARE_TYPE_USER;
1802
				$queryArgs[] = self::$shareTypeGroupUserUnique;
1803
				$queryArgs[] = $shareWith;
1804
1805
				$user = \OC::$server->getUserManager()->get($shareWith);
1806
				$groups = [];
1807
				if ($user) {
1808
					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1809
				}
1810
				if (!empty($groups)) {
1811
					$placeholders = join(',', array_fill(0, count($groups), '?'));
1812
					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1813
					$queryArgs[] = self::SHARE_TYPE_GROUP;
1814
					$queryArgs = array_merge($queryArgs, $groups);
1815
				}
1816
				$where .= ')';
1817
				// Don't include own group shares
1818
				$where .= ' AND `uid_owner` != ?';
1819
				$queryArgs[] = $shareWith;
1820
			} else {
1821
				$where .= ' AND `share_type` = ?';
1822
				$queryArgs[] = $shareType;
1823
				if (isset($shareWith)) {
1824
					$where .= ' AND `share_with` = ?';
1825
					$queryArgs[] = $shareWith;
1826
				}
1827
			}
1828
		}
1829
		if (isset($uidOwner)) {
1830
			$where .= ' AND `uid_owner` = ?';
1831
			$queryArgs[] = $uidOwner;
1832
			if (!isset($shareType)) {
1833
				// Prevent unique user targets for group shares from being selected
1834
				$where .= ' AND `share_type` != ?';
1835
				$queryArgs[] = self::$shareTypeGroupUserUnique;
1836
			}
1837
			if ($fileDependent) {
1838
				$column = 'file_source';
1839
			} else {
1840
				$column = 'item_source';
1841
			}
1842
		} else {
1843
			if ($fileDependent) {
1844
				$column = 'file_target';
1845
			} else {
1846
				$column = 'item_target';
1847
			}
1848
		}
1849
		if (isset($item)) {
1850
			$collectionTypes = self::getCollectionItemTypes($itemType);
1851
			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1852
				$where .= ' AND (';
1853
			} else {
1854
				$where .= ' AND';
1855
			}
1856
			// If looking for own shared items, check item_source else check item_target
1857
			if (isset($uidOwner) || $itemShareWithBySource) {
1858
				// If item type is a file, file source needs to be checked in case the item was converted
1859
				if ($fileDependent) {
1860
					$where .= ' `file_source` = ?';
1861
					$column = 'file_source';
1862
				} else {
1863
					$where .= ' `item_source` = ?';
1864
					$column = 'item_source';
1865
				}
1866
			} else {
1867
				if ($fileDependent) {
1868
					$where .= ' `file_target` = ?';
1869
					$item = \OC\Files\Filesystem::normalizePath($item);
1870
				} else {
1871
					$where .= ' `item_target` = ?';
1872
				}
1873
			}
1874
			$queryArgs[] = $item;
1875
			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1876
				$placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
1877
				$where .= ' OR `item_type` IN ('.$placeholders.'))';
1878
				$queryArgs = array_merge($queryArgs, $collectionTypes);
1879
			}
1880
		}
1881
1882
		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1883
			// Make sure the unique user target is returned if it exists,
1884
			// unique targets should follow the group share in the database
1885
			// If the limit is not 1, the filtering can be done later
1886
			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1887
		} else {
1888
			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1889
		}
1890
1891
		if ($limit != -1 && !$includeCollections) {
1892
			// The limit must be at least 3, because filtering needs to be done
1893
			if ($limit < 3) {
1894
				$queryLimit = 3;
1895
			} else {
1896
				$queryLimit = $limit;
1897
			}
1898
		} else {
1899
			$queryLimit = null;
1900
		}
1901
		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1902
		$root = strlen($root);
1903
		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1904
		$result = $query->execute($queryArgs);
1905 View Code Duplication
		if ($result === false) {
1906
			\OCP\Util::writeLog('OCP\Share',
1907
				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1908
				\OCP\Util::ERROR);
1909
		}
1910
		$items = array();
1911
		$targets = array();
1912
		$switchedItems = array();
1913
		$mounts = array();
1914
		while ($row = $result->fetchRow()) {
1915
			self::transformDBResults($row);
1916
			// Filter out duplicate group shares for users with unique targets
1917
			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1918
				continue;
1919
			}
1920
			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1921
				$row['share_type'] = self::SHARE_TYPE_GROUP;
1922
				$row['unique_name'] = true; // remember that we use a unique name for this user
1923
				$row['share_with'] = $items[$row['parent']]['share_with'];
1924
				// if the group share was unshared from the user we keep the permission, otherwise
1925
				// we take the permission from the parent because this is always the up-to-date
1926
				// permission for the group share
1927
				if ($row['permissions'] > 0) {
1928
					$row['permissions'] = $items[$row['parent']]['permissions'];
1929
				}
1930
				// Remove the parent group share
1931
				unset($items[$row['parent']]);
1932
				if ($row['permissions'] == 0) {
1933
					continue;
1934
				}
1935
			} else if (!isset($uidOwner)) {
1936
				// Check if the same target already exists
1937
				if (isset($targets[$row['id']])) {
1938
					// Check if the same owner shared with the user twice
1939
					// through a group and user share - this is allowed
1940
					$id = $targets[$row['id']];
1941
					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1942
						// Switch to group share type to ensure resharing conditions aren't bypassed
1943
						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1944
							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1945
							$items[$id]['share_with'] = $row['share_with'];
1946
						}
1947
						// Switch ids if sharing permission is granted on only
1948
						// one share to ensure correct parent is used if resharing
1949
						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1950
							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1951
							$items[$row['id']] = $items[$id];
1952
							$switchedItems[$id] = $row['id'];
1953
							unset($items[$id]);
1954
							$id = $row['id'];
1955
						}
1956
						$items[$id]['permissions'] |= (int)$row['permissions'];
1957
1958
					}
1959
					continue;
1960
				} elseif (!empty($row['parent'])) {
1961
					$targets[$row['parent']] = $row['id'];
1962
				}
1963
			}
1964
			// Remove root from file source paths if retrieving own shared items
1965
			if (isset($uidOwner) && isset($row['path'])) {
1966
				if (isset($row['parent'])) {
1967
					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1968
					$parentResult = $query->execute(array($row['parent']));
1969
					if ($result === false) {
1970
						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1971
							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1972
							\OCP\Util::ERROR);
1973
					} else {
1974
						$parentRow = $parentResult->fetchRow();
1975
						$tmpPath = $parentRow['file_target'];
1976
						// find the right position where the row path continues from the target path
1977
						$pos = strrpos($row['path'], $parentRow['file_target']);
1978
						$subPath = substr($row['path'], $pos);
1979
						$splitPath = explode('/', $subPath);
1980
						foreach (array_slice($splitPath, 2) as $pathPart) {
1981
							$tmpPath = $tmpPath . '/' . $pathPart;
1982
						}
1983
						$row['path'] = $tmpPath;
1984
					}
1985
				} else {
1986
					if (!isset($mounts[$row['storage']])) {
1987
						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1988
						if (is_array($mountPoints) && !empty($mountPoints)) {
1989
							$mounts[$row['storage']] = current($mountPoints);
1990
						}
1991
					}
1992
					if (!empty($mounts[$row['storage']])) {
1993
						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1994
						$relPath = substr($path, $root); // path relative to data/user
1995
						$row['path'] = rtrim($relPath, '/');
1996
					}
1997
				}
1998
			}
1999
2000
			if($checkExpireDate) {
2001
				if (self::expireItem($row)) {
2002
					continue;
2003
				}
2004
			}
2005
			// Check if resharing is allowed, if not remove share permission
2006
			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Util::isSharingDisabledForUser() has been deprecated with message: 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser

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

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

Loading history...
2007
				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
2008
			}
2009
			// Add display names to result
2010
			$row['share_with_displayname'] = $row['share_with'];
2011
			if ( isset($row['share_with']) && $row['share_with'] != '' &&
2012
				$row['share_type'] === self::SHARE_TYPE_USER) {
2013
				$row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getDisplayName() has been deprecated with message: 8.1.0 fetch \OCP\IUser (has getDisplayName()) by using method get() of \OCP\IUserManager - \OC::$server->getUserManager()

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

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

Loading history...
2014
			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
2015
				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
2016
				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
2017 View Code Duplication
				foreach ($addressBookEntries as $entry) {
2018
					foreach ($entry['CLOUD'] as $cloudID) {
2019
						if ($cloudID === $row['share_with']) {
2020
							$row['share_with_displayname'] = $entry['FN'];
2021
						}
2022
					}
2023
				}
2024
			}
2025
			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
2026
				$row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getDisplayName() has been deprecated with message: 8.1.0 fetch \OCP\IUser (has getDisplayName()) by using method get() of \OCP\IUserManager - \OC::$server->getUserManager()

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

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

Loading history...
2027
			}
2028
2029
			if ($row['permissions'] > 0) {
2030
				$items[$row['id']] = $row;
2031
			}
2032
2033
		}
2034
2035
		// group items if we are looking for items shared with the current user
2036
		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getUser() has been deprecated with message: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID()

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

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

Loading history...
2037
			$items = self::groupItems($items, $itemType);
2038
		}
2039
2040
		if (!empty($items)) {
2041
			$collectionItems = array();
2042
			foreach ($items as &$row) {
2043
				// Return only the item instead of a 2-dimensional array
2044
				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
2045
					if ($format == self::FORMAT_NONE) {
2046
						return $row;
2047
					} else {
2048
						break;
2049
					}
2050
				}
2051
				// Check if this is a collection of the requested item type
2052
				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
2053
					if (($collectionBackend = self::getBackend($row['item_type']))
2054
						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
2055
						// Collections can be inside collections, check if the item is a collection
2056
						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
2057
							$collectionItems[] = $row;
2058
						} else {
2059
							$collection = array();
2060
							$collection['item_type'] = $row['item_type'];
2061
							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2062
								$collection['path'] = basename($row['path']);
2063
							}
2064
							$row['collection'] = $collection;
2065
							// Fetch all of the children sources
2066
							$children = $collectionBackend->getChildren($row[$column]);
0 ignored issues
show
Documentation introduced by
$row[$column] is of type array<string,?>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2067
							foreach ($children as $child) {
2068
								$childItem = $row;
2069
								$childItem['item_type'] = $itemType;
2070
								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
2071
									$childItem['item_source'] = $child['source'];
2072
									$childItem['item_target'] = $child['target'];
2073
								}
2074
								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2075
									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2076
										$childItem['file_source'] = $child['source'];
2077
									} else { // TODO is this really needed if we already know that we use the file backend?
2078
										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
2079
										$childItem['file_source'] = $meta['fileid'];
2080
									}
2081
									$childItem['file_target'] =
2082
										\OC\Files\Filesystem::normalizePath($child['file_path']);
2083
								}
2084
								if (isset($item)) {
2085
									if ($childItem[$column] == $item) {
2086
										// Return only the item instead of a 2-dimensional array
2087
										if ($limit == 1) {
2088
											if ($format == self::FORMAT_NONE) {
2089
												return $childItem;
2090
											} else {
2091
												// Unset the items array and break out of both loops
2092
												$items = array();
2093
												$items[] = $childItem;
2094
												break 2;
2095
											}
2096
										} else {
2097
											$collectionItems[] = $childItem;
2098
										}
2099
									}
2100
								} else {
2101
									$collectionItems[] = $childItem;
2102
								}
2103
							}
2104
						}
2105
					}
2106
					// Remove collection item
2107
					$toRemove = $row['id'];
2108
					if (array_key_exists($toRemove, $switchedItems)) {
2109
						$toRemove = $switchedItems[$toRemove];
2110
					}
2111
					unset($items[$toRemove]);
2112
				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
2113
					// FIXME: Thats a dirty hack to improve file sharing performance,
2114
					// see github issue #10588 for more details
2115
					// Need to find a solution which works for all back-ends
2116
					$collectionBackend = self::getBackend($row['item_type']);
2117
					$sharedParents = $collectionBackend->getParents($row['item_source']);
2118
					foreach ($sharedParents as $parent) {
2119
						$collectionItems[] = $parent;
2120
					}
2121
				}
2122
			}
2123
			if (!empty($collectionItems)) {
2124
				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
2125
				$items = array_merge($items, $collectionItems);
2126
			}
2127
2128
			// filter out invalid items, these can appear when subshare entries exist
2129
			// for a group in which the requested user isn't a member any more
2130
			$items = array_filter($items, function($item) {
2131
				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
2132
			});
2133
2134
			return self::formatResult($items, $column, $backend, $format, $parameters);
2135
		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
2136
			// FIXME: Thats a dirty hack to improve file sharing performance,
2137
			// see github issue #10588 for more details
2138
			// Need to find a solution which works for all back-ends
2139
			$collectionItems = array();
2140
			$collectionBackend = self::getBackend('folder');
2141
			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
2142
			foreach ($sharedParents as $parent) {
2143
				$collectionItems[] = $parent;
2144
			}
2145
			if ($limit === 1) {
2146
				return reset($collectionItems);
2147
			}
2148
			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
2149
		}
2150
2151
		return array();
2152
	}
2153
2154
	/**
2155
	 * group items with link to the same source
2156
	 *
2157
	 * @param array $items
2158
	 * @param string $itemType
2159
	 * @return array of grouped items
2160
	 */
2161
	protected static function groupItems($items, $itemType) {
2162
2163
		$fileSharing = ($itemType === 'file' || $itemType === 'folder') ? true : false;
2164
2165
		$result = array();
2166
2167
		foreach ($items as $item) {
2168
			$grouped = false;
2169
			foreach ($result as $key => $r) {
2170
				// for file/folder shares we need to compare file_source, otherwise we compare item_source
2171
				// only group shares if they already point to the same target, otherwise the file where shared
2172
				// before grouping of shares was added. In this case we don't group them toi avoid confusions
2173
				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
2174
					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
2175
					// add the first item to the list of grouped shares
2176
					if (!isset($result[$key]['grouped'])) {
2177
						$result[$key]['grouped'][] = $result[$key];
2178
					}
2179
					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
2180
					$result[$key]['grouped'][] = $item;
2181
					$grouped = true;
2182
					break;
2183
				}
2184
			}
2185
2186
			if (!$grouped) {
2187
				$result[] = $item;
2188
			}
2189
2190
		}
2191
2192
		return $result;
2193
	}
2194
2195
	/**
2196
	 * Put shared item into the database
2197
	 * @param string $itemType Item type
2198
	 * @param string $itemSource Item source
2199
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
2200
	 * @param string $shareWith User or group the item is being shared with
2201
	 * @param string $uidOwner User that is the owner of shared item
2202
	 * @param int $permissions CRUDS permissions
2203
	 * @param boolean|array $parentFolder Parent folder target (optional)
2204
	 * @param string $token (optional)
2205
	 * @param string $itemSourceName name of the source item (optional)
2206
	 * @param \DateTime $expirationDate (optional)
2207
	 * @throws \Exception
2208
	 * @return mixed id of the new share or false
2209
	 */
2210
	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2211
								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
2212
2213
		$queriesToExecute = array();
2214
		$suggestedItemTarget = null;
2215
		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
2216
		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
2217
2218
		$result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
2219
		if(!empty($result)) {
2220
			$parent = $result['parent'];
2221
			$itemSource = $result['itemSource'];
2222
			$fileSource = $result['fileSource'];
2223
			$suggestedItemTarget = $result['suggestedItemTarget'];
2224
			$suggestedFileTarget = $result['suggestedFileTarget'];
2225
			$filePath = $result['filePath'];
2226
		}
2227
2228
		$isGroupShare = false;
2229
		if ($shareType == self::SHARE_TYPE_GROUP) {
2230
			$isGroupShare = true;
2231
			if (isset($shareWith['users'])) {
2232
				$users = $shareWith['users'];
2233
			} else {
2234
				$group = \OC::$server->getGroupManager()->get($shareWith['group']);
2235 View Code Duplication
				if ($group) {
2236
					$users = $group->searchUsers('', -1, 0);
2237
					$userIds = [];
2238
					foreach ($users as $user) {
2239
						$userIds[] = $user->getUID();
2240
					}
2241
					$users = $userIds;
2242
				} else {
2243
					$users = [];
2244
				}
2245
			}
2246
			// remove current user from list
2247
			if (in_array(\OCP\User::getUser(), $users)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getUser() has been deprecated with message: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID()

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

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

Loading history...
2248
				unset($users[array_search(\OCP\User::getUser(), $users)]);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::getUser() has been deprecated with message: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID()

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

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

Loading history...
2249
			}
2250
			$groupItemTarget = Helper::generateTarget($itemType, $itemSource,
2251
				$shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
2252
			$groupFileTarget = Helper::generateTarget($itemType, $itemSource,
2253
				$shareType, $shareWith['group'], $uidOwner, $filePath);
2254
2255
			// add group share to table and remember the id as parent
2256
			$queriesToExecute['groupShare'] = array(
2257
				'itemType'			=> $itemType,
2258
				'itemSource'		=> $itemSource,
2259
				'itemTarget'		=> $groupItemTarget,
2260
				'shareType'			=> $shareType,
2261
				'shareWith'			=> $shareWith['group'],
2262
				'uidOwner'			=> $uidOwner,
2263
				'permissions'		=> $permissions,
2264
				'shareTime'			=> time(),
2265
				'fileSource'		=> $fileSource,
2266
				'fileTarget'		=> $groupFileTarget,
2267
				'token'				=> $token,
2268
				'parent'			=> $parent,
2269
				'expiration'		=> $expirationDate,
2270
			);
2271
2272
		} else {
2273
			$users = array($shareWith);
2274
			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2275
				$suggestedItemTarget);
2276
		}
2277
2278
		$run = true;
2279
		$error = '';
2280
		$preHookData = array(
2281
			'itemType' => $itemType,
2282
			'itemSource' => $itemSource,
2283
			'shareType' => $shareType,
2284
			'uidOwner' => $uidOwner,
2285
			'permissions' => $permissions,
2286
			'fileSource' => $fileSource,
2287
			'expiration' => $expirationDate,
2288
			'token' => $token,
2289
			'run' => &$run,
2290
			'error' => &$error
2291
		);
2292
2293
		$preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2294
		$preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2295
2296
		\OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
2297
2298
		if ($run === false) {
2299
			throw new \Exception($error);
2300
		}
2301
2302
		foreach ($users as $user) {
0 ignored issues
show
Bug introduced by
The expression $users of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
2303
			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
2304
			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
2305
2306
			$userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
2307
2308
			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...
2309
				$fileTarget = $sourceExists['file_target'];
2310
				$itemTarget = $sourceExists['item_target'];
2311
2312
				// for group shares we don't need a additional entry if the target is the same
2313
				if($isGroupShare && $groupItemTarget === $itemTarget) {
2314
					continue;
2315
				}
2316
2317
			} 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...
2318
2319
				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
2320
					$uidOwner, $suggestedItemTarget, $parent);
2321
				if (isset($fileSource)) {
2322
					if ($parentFolder) {
2323
						if ($parentFolder === true) {
2324
							$fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
2325
								$uidOwner, $suggestedFileTarget, $parent);
2326
							if ($fileTarget != $groupFileTarget) {
2327
								$parentFolders[$user]['folder'] = $fileTarget;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$parentFolders was never initialized. Although not strictly required by PHP, it is generally a good practice to add $parentFolders = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2328
							}
2329
						} else if (isset($parentFolder[$user])) {
2330
							$fileTarget = $parentFolder[$user]['folder'].$itemSource;
2331
							$parent = $parentFolder[$user]['id'];
2332
						}
2333
					} else {
2334
						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
2335
							$user, $uidOwner, $suggestedFileTarget, $parent);
2336
					}
2337
				} else {
2338
					$fileTarget = null;
2339
				}
2340
2341
			} else {
2342
2343
				// group share which doesn't exists until now, check if we need a unique target for this user
2344
2345
				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
2346
					$uidOwner, $suggestedItemTarget, $parent);
2347
2348
				// do we also need a file target
2349
				if (isset($fileSource)) {
2350
					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
2351
						$uidOwner, $suggestedFileTarget, $parent);
2352
				} else {
2353
					$fileTarget = null;
2354
				}
2355
2356
				if (($itemTarget === $groupItemTarget) &&
2357
					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
2358
					continue;
2359
				}
2360
			}
2361
2362
			$queriesToExecute[] = array(
2363
				'itemType'			=> $itemType,
2364
				'itemSource'		=> $itemSource,
2365
				'itemTarget'		=> $itemTarget,
2366
				'shareType'			=> $userShareType,
2367
				'shareWith'			=> $user,
2368
				'uidOwner'			=> $uidOwner,
2369
				'permissions'		=> $permissions,
2370
				'shareTime'			=> time(),
2371
				'fileSource'		=> $fileSource,
2372
				'fileTarget'		=> $fileTarget,
2373
				'token'				=> $token,
2374
				'parent'			=> $parent,
2375
				'expiration'		=> $expirationDate,
2376
			);
2377
2378
		}
2379
2380
		$id = false;
2381
		if ($isGroupShare) {
2382
			$id = self::insertShare($queriesToExecute['groupShare']);
2383
			// Save this id, any extra rows for this group share will need to reference it
2384
			$parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2385
			unset($queriesToExecute['groupShare']);
2386
		}
2387
2388
		foreach ($queriesToExecute as $shareQuery) {
2389
			$shareQuery['parent'] = $parent;
2390
			$id = self::insertShare($shareQuery);
2391
		}
2392
2393
		$postHookData = array(
2394
			'itemType' => $itemType,
2395
			'itemSource' => $itemSource,
2396
			'parent' => $parent,
2397
			'shareType' => $shareType,
2398
			'uidOwner' => $uidOwner,
2399
			'permissions' => $permissions,
2400
			'fileSource' => $fileSource,
2401
			'id' => $parent,
2402
			'token' => $token,
2403
			'expirationDate' => $expirationDate,
2404
		);
2405
2406
		$postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2407
		$postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2408
		$postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
2409
2410
		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
2411
2412
2413
		return $id ? $id : false;
2414
	}
2415
2416
	/**
2417
	 * @param string $itemType
2418
	 * @param string $itemSource
2419
	 * @param int $shareType
2420
	 * @param string $shareWith
2421
	 * @param string $uidOwner
2422
	 * @param int $permissions
2423
	 * @param string|null $itemSourceName
2424
	 * @param null|\DateTime $expirationDate
2425
	 */
2426
	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
2427
		$backend = self::getBackend($itemType);
2428
2429
		$l = \OC::$server->getL10N('lib');
2430
		$result = array();
2431
2432
		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
2433
2434
		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
2435
		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...
2436
			// Check if attempting to share back to owner
2437
			if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
2438
				$message = 'Sharing %s failed, because the user %s is the original sharer';
2439
				$message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
2440
2441
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
2442
				throw new \Exception($message_t);
2443
			}
2444
		}
2445
2446
		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
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...
2447
			// Check if share permissions is granted
2448
			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
2449
				if (~(int)$checkReshare['permissions'] & $permissions) {
2450
					$message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
2451
					$message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
2452
2453
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
2454
					throw new \Exception($message_t);
2455
				} else {
2456
					// TODO Don't check if inside folder
2457
					$result['parent'] = $checkReshare['id'];
2458
2459
					$result['expirationDate'] = $expirationDate;
2460
					// $checkReshare['expiration'] could be null and then is always less than any value
2461
					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
2462
						$result['expirationDate'] = $checkReshare['expiration'];
2463
					}
2464
2465
					// only suggest the same name as new target if it is a reshare of the
2466
					// same file/folder and not the reshare of a child
2467
					if ($checkReshare[$column] === $itemSource) {
2468
						$result['filePath'] = $checkReshare['file_target'];
2469
						$result['itemSource'] = $checkReshare['item_source'];
2470
						$result['fileSource'] = $checkReshare['file_source'];
2471
						$result['suggestedItemTarget'] = $checkReshare['item_target'];
2472
						$result['suggestedFileTarget'] = $checkReshare['file_target'];
2473
					} else {
2474
						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
2475
						$result['suggestedItemTarget'] = null;
2476
						$result['suggestedFileTarget'] = null;
2477
						$result['itemSource'] = $itemSource;
2478
						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
2479
					}
2480
				}
2481 View Code Duplication
			} else {
2482
				$message = 'Sharing %s failed, because resharing is not allowed';
2483
				$message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
2484
2485
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
2486
				throw new \Exception($message_t);
2487
			}
2488
		} else {
2489
			$result['parent'] = null;
2490
			$result['suggestedItemTarget'] = null;
2491
			$result['suggestedFileTarget'] = null;
2492
			$result['itemSource'] = $itemSource;
2493
			$result['expirationDate'] = $expirationDate;
2494 View Code Duplication
			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...
2495
				$message = 'Sharing %s failed, because the sharing backend for '
2496
					.'%s could not find its source';
2497
				$message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
2498
				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
2499
				throw new \Exception($message_t);
2500
			}
2501
			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2502
				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
2503
				if ($itemType == 'file' || $itemType == 'folder') {
2504
					$result['fileSource'] = $itemSource;
2505
				} else {
2506
					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
0 ignored issues
show
Security Bug introduced by
It seems like $result['filePath'] can also be of type false; however, OC\Files\Filesystem::getFileInfo() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
2507
					$result['fileSource'] = $meta['fileid'];
2508
				}
2509 View Code Duplication
				if ($result['fileSource'] == -1) {
2510
					$message = 'Sharing %s failed, because the file could not be found in the file cache';
2511
					$message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
2512
2513
					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
2514
					throw new \Exception($message_t);
2515
				}
2516
			} else {
2517
				$result['filePath'] = null;
2518
				$result['fileSource'] = null;
2519
			}
2520
		}
2521
2522
		return $result;
2523
	}
2524
2525
	/**
2526
	 *
2527
	 * @param array $shareData
2528
	 * @return mixed false in case of a failure or the id of the new share
2529
	 */
2530
	private static function insertShare(array $shareData) {
2531
2532
		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
2533
			.' `item_type`, `item_source`, `item_target`, `share_type`,'
2534
			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
2535
			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
2536
		$query->bindValue(1, $shareData['itemType']);
2537
		$query->bindValue(2, $shareData['itemSource']);
2538
		$query->bindValue(3, $shareData['itemTarget']);
2539
		$query->bindValue(4, $shareData['shareType']);
2540
		$query->bindValue(5, $shareData['shareWith']);
2541
		$query->bindValue(6, $shareData['uidOwner']);
2542
		$query->bindValue(7, $shareData['permissions']);
2543
		$query->bindValue(8, $shareData['shareTime']);
2544
		$query->bindValue(9, $shareData['fileSource']);
2545
		$query->bindValue(10, $shareData['fileTarget']);
2546
		$query->bindValue(11, $shareData['token']);
2547
		$query->bindValue(12, $shareData['parent']);
2548
		$query->bindValue(13, $shareData['expiration'], 'datetime');
2549
		$result = $query->execute();
2550
2551
		$id = false;
2552
		if ($result) {
2553
			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2554
		}
2555
2556
		return $id;
2557
2558
	}
2559
2560
	/**
2561
	 * Delete all shares with type SHARE_TYPE_LINK
2562
	 */
2563
	public static function removeAllLinkShares() {
2564
		// Delete any link shares
2565
		$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?');
2566
		$result = $query->execute(array(self::SHARE_TYPE_LINK));
2567
		while ($item = $result->fetchRow()) {
2568
			Helper::delete($item['id']);
2569
		}
2570
	}
2571
2572
	/**
2573
	 * In case a password protected link is not yet authenticated this function will return false
2574
	 *
2575
	 * @param array $linkItem
2576
	 * @return boolean
2577
	 */
2578
	public static function checkPasswordProtectedShare(array $linkItem) {
2579
		if (!isset($linkItem['share_with'])) {
2580
			return true;
2581
		}
2582
		if (!isset($linkItem['share_type'])) {
2583
			return true;
2584
		}
2585
		if (!isset($linkItem['id'])) {
2586
			return true;
2587
		}
2588
2589
		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
2590
			return true;
2591
		}
2592
2593 View Code Duplication
		if ( \OC::$server->getSession()->exists('public_link_authenticated')
2594
			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
2595
			return true;
2596
		}
2597
2598
		return false;
2599
	}
2600
2601
	/**
2602
	 * construct select statement
2603
	 * @param int $format
2604
	 * @param boolean $fileDependent ist it a file/folder share or a generla share
2605
	 * @param string $uidOwner
2606
	 * @return string select statement
2607
	 */
2608
	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
2609
		$select = '*';
2610
		if ($format == self::FORMAT_STATUSES) {
2611
			if ($fileDependent) {
2612
				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
2613
					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
2614
					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2615
					. '`uid_initiator`';
2616
			} else {
2617
				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
2618
			}
2619
		} else {
2620
			if (isset($uidOwner)) {
2621
				if ($fileDependent) {
2622
					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
2623
						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
2624
						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
2625
						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2626
				} else {
2627
					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
2628
						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
2629
				}
2630
			} else {
2631
				if ($fileDependent) {
2632
					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
2633
						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
2634
							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
2635
							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2636
							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
2637
					} else {
2638
						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
2639
							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
2640
							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
2641
						    . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
2642
							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2643
					}
2644
				}
2645
			}
2646
		}
2647
		return $select;
2648
	}
2649
2650
2651
	/**
2652
	 * transform db results
2653
	 * @param array $row result
2654
	 */
2655
	private static function transformDBResults(&$row) {
2656
		if (isset($row['id'])) {
2657
			$row['id'] = (int) $row['id'];
2658
		}
2659
		if (isset($row['share_type'])) {
2660
			$row['share_type'] = (int) $row['share_type'];
2661
		}
2662
		if (isset($row['parent'])) {
2663
			$row['parent'] = (int) $row['parent'];
2664
		}
2665
		if (isset($row['file_parent'])) {
2666
			$row['file_parent'] = (int) $row['file_parent'];
2667
		}
2668
		if (isset($row['file_source'])) {
2669
			$row['file_source'] = (int) $row['file_source'];
2670
		}
2671
		if (isset($row['permissions'])) {
2672
			$row['permissions'] = (int) $row['permissions'];
2673
		}
2674
		if (isset($row['storage'])) {
2675
			$row['storage'] = (int) $row['storage'];
2676
		}
2677
		if (isset($row['stime'])) {
2678
			$row['stime'] = (int) $row['stime'];
2679
		}
2680
		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
2681
			// discard expiration date for non-link shares, which might have been
2682
			// set by ancient bugs
2683
			$row['expiration'] = null;
2684
		}
2685
	}
2686
2687
	/**
2688
	 * format result
2689
	 * @param array $items result
2690
	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
2691
	 * @param \OCP\Share_Backend $backend sharing backend
2692
	 * @param int $format
2693
	 * @param array $parameters additional format parameters
2694
	 * @return array format result
2695
	 */
2696
	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
2697
		if ($format === self::FORMAT_NONE) {
2698
			return $items;
2699
		} else if ($format === self::FORMAT_STATUSES) {
2700
			$statuses = array();
2701
			foreach ($items as $item) {
2702
				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
2703
					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
2704
						continue;
2705
					}
2706
					$statuses[$item[$column]]['link'] = true;
2707
				} else if (!isset($statuses[$item[$column]])) {
2708
					$statuses[$item[$column]]['link'] = false;
2709
				}
2710
				if (!empty($item['file_target'])) {
2711
					$statuses[$item[$column]]['path'] = $item['path'];
2712
				}
2713
			}
2714
			return $statuses;
2715
		} else {
2716
			return $backend->formatItems($items, $format, $parameters);
2717
		}
2718
	}
2719
2720
	/**
2721
	 * remove protocol from URL
2722
	 *
2723
	 * @param string $url
2724
	 * @return string
2725
	 */
2726 View Code Duplication
	public static function removeProtocolFromUrl($url) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2727
		if (strpos($url, 'https://') === 0) {
2728
			return substr($url, strlen('https://'));
2729
		} else if (strpos($url, 'http://') === 0) {
2730
			return substr($url, strlen('http://'));
2731
		}
2732
2733
		return $url;
2734
	}
2735
2736
	/**
2737
	 * try http post first with https and then with http as a fallback
2738
	 *
2739
	 * @param string $remoteDomain
2740
	 * @param string $urlSuffix
2741
	 * @param array $fields post parameters
2742
	 * @return array
2743
	 */
2744
	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
2745
		$protocol = 'https://';
2746
		$result = [
2747
			'success' => false,
2748
			'result' => '',
2749
		];
2750
		$try = 0;
2751
		$discoveryManager = new DiscoveryManager(
2752
			\OC::$server->getMemCacheFactory(),
2753
			\OC::$server->getHTTPClientService()
2754
		);
2755
		while ($result['success'] === false && $try < 2) {
2756
			$endpoint = $discoveryManager->getShareEndpoint($protocol . $remoteDomain);
2757
			$result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
0 ignored issues
show
Deprecated Code introduced by
The method OC\Server::getHTTPHelper() has been deprecated with message: Use getHTTPClientService()

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

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

Loading history...
Deprecated Code introduced by
The method OC\HTTPHelper::post() has been deprecated with message: Use \OCP\Http\Client\IClientService

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

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

Loading history...
2758
			$try++;
2759
			$protocol = 'http://';
2760
		}
2761
2762
		return $result;
2763
	}
2764
2765
	/**
2766
	 * send server-to-server share to remote server
2767
	 *
2768
	 * @param string $token
2769
	 * @param string $shareWith
2770
	 * @param string $name
2771
	 * @param int $remote_id
2772
	 * @param string $owner
2773
	 * @return bool
2774
	 */
2775
	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2776
2777
		list($user, $remote) = Helper::splitUserRemote($shareWith);
2778
2779
		if ($user && $remote) {
2780
			$url = $remote;
2781
2782
			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2783
2784
			$fields = array(
2785
				'shareWith' => $user,
2786
				'token' => $token,
2787
				'name' => $name,
2788
				'remoteId' => $remote_id,
2789
				'owner' => $owner,
2790
				'remote' => $local,
2791
			);
2792
2793
			$url = self::removeProtocolFromUrl($url);
2794
			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2795
			$status = json_decode($result['result'], true);
2796
2797 View Code Duplication
			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2798
				\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
2799
				return true;
2800
			}
2801
2802
		}
2803
2804
		return false;
2805
	}
2806
2807
	/**
2808
	 * send server-to-server unshare to remote server
2809
	 *
2810
	 * @param string $remote url
2811
	 * @param int $id share id
2812
	 * @param string $token
2813
	 * @return bool
2814
	 */
2815
	private static function sendRemoteUnshare($remote, $id, $token) {
2816
		$url = rtrim($remote, '/');
2817
		$fields = array('token' => $token, 'format' => 'json');
2818
		$url = self::removeProtocolFromUrl($url);
2819
		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2820
		$status = json_decode($result['result'], true);
2821
2822
		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2823
	}
2824
2825
	/**
2826
	 * check if user can only share with group members
2827
	 * @return bool
2828
	 */
2829
	public static function shareWithGroupMembersOnly() {
2830
		$value = \OC::$server->getAppConfig()->getValue('core', 'shareapi_only_share_with_group_members', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
2831
		return ($value === 'yes') ? true : false;
2832
	}
2833
2834
	/**
2835
	 * @return bool
2836
	 */
2837
	public static function isDefaultExpireDateEnabled() {
2838
		$defaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
2839
		return ($defaultExpireDateEnabled === "yes") ? true : false;
2840
	}
2841
2842
	/**
2843
	 * @return bool
2844
	 */
2845
	public static function enforceDefaultExpireDate() {
2846
		$enforceDefaultExpireDate = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
2847
		return ($enforceDefaultExpireDate === "yes") ? true : false;
2848
	}
2849
2850
	/**
2851
	 * @return int
2852
	 */
2853
	public static function getExpireInterval() {
2854
		return (int)\OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
2855
	}
2856
2857
	/**
2858
	 * Checks whether the given path is reachable for the given owner
2859
	 *
2860
	 * @param string $path path relative to files
2861
	 * @param string $ownerStorageId storage id of the owner
2862
	 *
2863
	 * @return boolean true if file is reachable, false otherwise
2864
	 */
2865
	private static function isFileReachable($path, $ownerStorageId) {
2866
		// if outside the home storage, file is always considered reachable
2867
		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2868
			substr($ownerStorageId, 0, 13) === 'object::user:'
2869
		)) {
2870
			return true;
2871
		}
2872
2873
		// if inside the home storage, the file has to be under "/files/"
2874
		$path = ltrim($path, '/');
2875
		if (substr($path, 0, 6) === 'files/') {
2876
			return true;
2877
		}
2878
2879
		return false;
2880
	}
2881
2882
	/**
2883
	 * @param IConfig $config
2884
	 * @return bool 
2885
	 */
2886
	public static function enforcePassword(IConfig $config) {
2887
		$enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2888
		return ($enforcePassword === "yes") ? true : false;
2889
	}
2890
2891
	/**
2892
	 * Get all share entries, including non-unique group items
2893
	 *
2894
	 * @param string $owner
2895
	 * @return array
2896
	 */
2897
	public static function getAllSharesForOwner($owner) {
2898
		$query = 'SELECT * FROM `*PREFIX*share` WHERE `uid_owner` = ?';
2899
		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$owner]);
2900
		return $result->fetchAll();
2901
	}
2902
2903
	/**
2904
	 * Get all share entries, including non-unique group items for a file
2905
	 *
2906
	 * @param int $id
2907
	 * @return array
2908
	 */
2909
	public static function getAllSharesForFileId($id) {
2910
		$query = 'SELECT * FROM `*PREFIX*share` WHERE `file_source` = ?';
2911
		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$id]);
2912
		return $result->fetchAll();
2913
	}
2914
2915
	/**
2916
	 * @param string $password
2917
	 * @throws \Exception
2918
	 */
2919
	private static function verifyPassword($password) {
2920
2921
		$accepted = true;
2922
		$message = '';
2923
		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2924
			'password' => $password,
2925
			'accepted' => &$accepted,
2926
			'message' => &$message
2927
		]);
2928
2929
		if (!$accepted) {
2930
			throw new \Exception($message);
2931
		}
2932
	}
2933
}
2934