Completed
Pull Request — master (#26608)
by
unknown
09:04
created

Share::createSelectStatement()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Bart Visscher <[email protected]>
5
 * @author Bernhard Reiter <[email protected]>
6
 * @author Björn Schießle <[email protected]>
7
 * @author Christopher Schäpers <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Daniel Hansson <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Jörn Friedrich Dreyer <[email protected]>
12
 * @author Lukas Reschke <[email protected]>
13
 * @author Michael Kuhn <[email protected]>
14
 * @author Morris Jobke <[email protected]>
15
 * @author Robin Appelman <[email protected]>
16
 * @author Robin McCorkell <[email protected]>
17
 * @author Roeland Jago Douma <[email protected]>
18
 * @author Sebastian Döll <[email protected]>
19
 * @author Stefan Weil <[email protected]>
20
 * @author Thomas Müller <[email protected]>
21
 * @author Torben Dannhauer <[email protected]>
22
 * @author Vincent Petry <[email protected]>
23
 * @author Volkan Gezer <[email protected]>
24
 *
25
 * @copyright Copyright (c) 2018, ownCloud GmbH
26
 * @license AGPL-3.0
27
 *
28
 * This code is free software: you can redistribute it and/or modify
29
 * it under the terms of the GNU Affero General Public License, version 3,
30
 * as published by the Free Software Foundation.
31
 *
32
 * This program is distributed in the hope that it will be useful,
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
 * GNU Affero General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU Affero General Public License, version 3,
38
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
39
 *
40
 */
41
42
namespace OC\Share;
43
44
use OC\Files\Filesystem;
45
use OC\Group\Group;
46
use OCA\FederatedFileSharing\DiscoveryManager;
47
use OCP\DB\QueryBuilder\IQueryBuilder;
48
use OCP\IUser;
49
use OCP\IUserSession;
50
use OCP\IDBConnection;
51
use OCP\IConfig;
52
use Symfony\Component\EventDispatcher\GenericEvent;
53
54
/**
55
 * This class provides the ability for apps to share their content between users.
56
 *
57
 * It provides the following hooks:
58
 *  - post_shared
59
 */
60
class Share extends Constants {
61
62
	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
63
	 * Construct permissions for share() and setPermissions with Or (|) e.g.
64
	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
65
	 *
66
	 * Check if permission is granted with And (&) e.g. Check if delete is
67
	 * granted: if ($permissions & PERMISSION_DELETE)
68
	 *
69
	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
70
	 * permission: $permissions &= ~PERMISSION_UPDATE
71
	 *
72
	 * Apps are required to handle permissions on their own, this class only
73
	 * stores and manages the permissions of shares
74
	 * @see lib/public/constants.php
75
	 */
76
77
	/**
78
	 * Check if the Share API is enabled
79
	 * @return boolean true if enabled or false
80
	 *
81
	 * The Share API is enabled by default if not configured
82
	 */
83
	public static function isEnabled() {
84
		if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
85
			return true;
86
		}
87
		return false;
88
	}
89
90
	/**
91
	 * Find which users can access a shared item
92
	 * @param string $path to the file
93
	 * @param string $ownerUser owner of the file
94
	 * @param boolean $includeOwner include owner to the list of users with access to the file
95
	 * @param boolean $returnUserPaths Return an array with the user => path map
96
	 * @param boolean $recursive take all parent folders into account (default true)
97
	 * @return array
98
	 * @note $path needs to be relative to user data dir, e.g. 'file.txt'
99
	 *       not '/admin/data/file.txt'
100
	 */
101
	public static function getUsersSharingFile($path, $ownerUser, $includeOwner = false, $returnUserPaths = false, $recursive = true) {
102
		// FIXME: make ths use IShareProvider::getSharesByPath and extract users
103
		$userManager = \OC::$server->getUserManager();
104
		$userObject = $userManager->get($ownerUser);
105
106 View Code Duplication
		if ($userObject === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
107
			$msg = "Backends provided no user object for $ownerUser";
108
			\OC::$server->getLogger()->error($msg, ['app' => __CLASS__]);
109
			throw new \OC\User\NoUserException($msg);
110
		}
111
112
		$ownerUser = $userObject->getUID();
113
114
		Filesystem::initMountPoints($ownerUser);
115
		$shares = $sharePaths = $fileTargets = [];
116
		$publicShare = false;
117
		$remoteShare = false;
118
		$source = -1;
119
		$cache = $mountPath = false;
120
121
		$view = new \OC\Files\View('/' . $ownerUser . '/files');
122
		$meta = $view->getFileInfo($path);
123
		if ($meta) {
124
			$path = \substr($meta->getPath(), \strlen('/' . $ownerUser . '/files'));
125
		} else {
126
			// if the file doesn't exists yet we start with the parent folder
127
			$meta = $view->getFileInfo(\dirname($path));
128
		}
129
130
		if ($meta !== false) {
131
			$source = $meta['fileid'];
132
			$cache = new \OC\Files\Cache\Cache($meta['storage']);
133
134
			$mountPath = $meta->getMountPoint()->getMountPoint();
135
			if ($mountPath !== false) {
136
				$mountPath = \substr($mountPath, \strlen('/' . $ownerUser . '/files'));
137
			}
138
		}
139
140
		$paths = [];
141
		while ($source !== -1) {
142
			// Fetch all shares with another user
143
			if (!$returnUserPaths) {
144
				$query = \OC_DB::prepare(
145
					'SELECT `share_with`, `file_source`, `file_target`
146
					FROM
147
					`*PREFIX*share`
148
					WHERE
149
					`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
150
				);
151
				$result = $query->execute([$source, self::SHARE_TYPE_USER]);
152
			} else {
153
				$query = \OC_DB::prepare(
154
					'SELECT `share_with`, `file_source`, `file_target`
155
				FROM
156
				`*PREFIX*share`
157
				WHERE
158
				`item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')'
159
				);
160
				$result = $query->execute([$source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique]);
161
			}
162
163
			if (\OCP\DB::isError($result)) {
164
				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
165
			} else {
166
				while ($row = $result->fetchRow()) {
167
					$shares[] = $row['share_with'];
168
					if ($returnUserPaths) {
169
						$fileTargets[(int) $row['file_source']][$row['share_with']] = $row;
170
					}
171
				}
172
			}
173
174
			// We also need to take group shares into account
175
			$query = \OC_DB::prepare(
176
				'SELECT `share_with`, `file_source`, `file_target`
177
				FROM
178
				`*PREFIX*share`
179
				WHERE
180
				`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
181
			);
182
183
			$result = $query->execute([$source, self::SHARE_TYPE_GROUP]);
184
185
			if (\OCP\DB::isError($result)) {
186
				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
187
			} else {
188
				while ($row = $result->fetchRow()) {
189
					$usersInGroup = self::usersInGroup($row['share_with']);
190
					$shares = \array_merge($shares, $usersInGroup);
191
					if ($returnUserPaths) {
192
						foreach ($usersInGroup as $user) {
193
							if (!isset($fileTargets[(int) $row['file_source']][$user])) {
194
								// When the user already has an entry for this file source
195
								// the file is either shared directly with him as well, or
196
								// he has an exception entry (because of naming conflict).
197
								$fileTargets[(int) $row['file_source']][$user] = $row;
198
							}
199
						}
200
					}
201
				}
202
			}
203
204
			//check for public link shares
205 View Code Duplication
			if (!$publicShare) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
206
				$query = \OC_DB::prepare('
207
					SELECT `share_with`
208
					FROM `*PREFIX*share`
209
					WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
210
				);
211
212
				$result = $query->execute([$source, self::SHARE_TYPE_LINK]);
213
214
				if (\OCP\DB::isError($result)) {
215
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
216
				} else {
217
					if ($result->fetchRow()) {
218
						$publicShare = true;
219
					}
220
				}
221
			}
222
223
			//check for remote share
224 View Code Duplication
			if (!$remoteShare) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
225
				$query = \OC_DB::prepare('
226
					SELECT `share_with`
227
					FROM `*PREFIX*share`
228
					WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
229
				);
230
231
				$result = $query->execute([$source, self::SHARE_TYPE_REMOTE]);
232
233
				if (\OCP\DB::isError($result)) {
234
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
235
				} else {
236
					if ($result->fetchRow()) {
237
						$remoteShare = true;
238
					}
239
				}
240
			}
241
242
			// let's get the parent for the next round
243
			$meta = $cache->get((int)$source);
244
			if ($recursive === true && $meta !== false) {
245
				$paths[$source] = $meta['path'];
246
				$source = (int)$meta['parent'];
247
			} else {
248
				$source = -1;
249
			}
250
		}
251
252
		// Include owner in list of users, if requested
253
		if ($includeOwner) {
254
			$shares[] = $ownerUser;
255
		}
256
257
		if ($returnUserPaths) {
258
			$fileTargetIDs = \array_keys($fileTargets);
259
			$fileTargetIDs = \array_unique($fileTargetIDs);
260
261
			if (!empty($fileTargetIDs)) {
262
				$query = \OC_DB::prepare(
263
					'SELECT `fileid`, `path`
264
					FROM `*PREFIX*filecache`
265
					WHERE `fileid` IN (' . \implode(',', $fileTargetIDs) . ')'
266
				);
267
				$result = $query->execute();
268
269
				if (\OCP\DB::isError($result)) {
270
					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
271
				} else {
272
					while ($row = $result->fetchRow()) {
273
						foreach ($fileTargets[$row['fileid']] as $uid => $shareData) {
274
							if ($mountPath !== false) {
275
								$sharedPath = $shareData['file_target'];
276
								$sharedPath .= \substr($path, \strlen($mountPath) + \strlen($paths[$row['fileid']]));
277
								$sharePaths[$uid] = $sharedPath;
278
							} else {
279
								$sharedPath = $shareData['file_target'];
280
								$sharedPath .= \substr($path, \strlen($row['path']) -5);
281
								$sharePaths[$uid] = $sharedPath;
282
							}
283
						}
284
					}
285
				}
286
			}
287
288
			if ($includeOwner) {
289
				$sharePaths[$ownerUser] = $path;
290
			} else {
291
				unset($sharePaths[$ownerUser]);
292
			}
293
294
			return $sharePaths;
295
		}
296
297
		return ['users' => \array_unique($shares), 'public' => $publicShare, 'remote' => $remoteShare];
298
	}
299
300
	/**
301
	 * Based on the given token the share information will be returned - password protected shares will be verified
302
	 * @param string $token
303
	 * @param bool $checkPasswordProtection
304
	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
305
	 */
306
	public static function getShareByToken($token, $checkPasswordProtection = true) {
307
		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
308
		$result = $query->execute([$token]);
309
		if ($result === false) {
310
			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
311
		}
312
		$row = $result->fetchRow();
313
		if ($row === false) {
314
			return false;
315
		}
316
		if (\is_array($row) and self::expireItem($row)) {
317
			return false;
318
		}
319
320
		// password protected shares need to be authenticated
321
		if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) {
322
			return false;
323
		}
324
325
		return $row;
326
	}
327
328
	/**
329
	 * resolves reshares down to the last real share
330
	 * @param array $linkItem
331
	 * @return array item owner
332
	 */
333
	public static function resolveReShare($linkItem) {
334
		if (isset($linkItem['parent'])) {
335
			$parent = $linkItem['parent'];
336
			while (isset($parent)) {
337
				$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
338
				$item = $query->execute([$parent])->fetchRow();
339
				if (isset($item['parent'])) {
340
					$parent = $item['parent'];
341
				} else {
342
					return $item;
343
				}
344
			}
345
		}
346
		return $linkItem;
347
	}
348
349
	/**
350
	 * sent status if users got informed by mail about share
351
	 * @param string $itemType
352
	 * @param string $itemSource
353
	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
354
	 * @param string $recipient with whom was the file shared
355
	 * @param boolean $status
356
	 */
357
	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
358
		$status = $status ? 1 : 0;
359
360
		$query = \OC_DB::prepare(
361
			'UPDATE `*PREFIX*share`
362
					SET `mail_send` = ?
363
					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
364
365
		$result = $query->execute([$status, $itemType, $itemSource, $shareType, $recipient]);
366
367
		if ($result === false) {
368
			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
369
		}
370
	}
371
372
	/**
373
	 * Checks whether a share has expired, calls unshareItem() if yes.
374
	 * @param array $item Share data (usually database row)
375
	 * @return boolean True if item was expired, false otherwise.
376
	 */
377
	protected static function expireItem(array $item) {
378
		$result = false;
379
380
		// only use default expiration date for link shares
381
		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
382
383
			// calculate expiration date
384
			if (!empty($item['expiration'])) {
385
				$userDefinedExpire = new \DateTime($item['expiration']);
386
				$expires = $userDefinedExpire->getTimestamp();
387
			} else {
388
				$expires = null;
389
			}
390
391
			// get default expiration settings
392
			$defaultSettings = Helper::getDefaultExpireSetting();
393
			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
394
395
			if (\is_int($expires)) {
396
				$now = \time();
397
				if ($now > $expires) {
398
					self::unshareItem($item);
399
					$result = true;
400
				}
401
			}
402
		}
403
		return $result;
404
	}
405
406
	/**
407
	 * Unshares a share given a share data array
408
	 * @param array $item Share data (usually database row)
409
	 * @param int $newParent parent ID
410
	 * @return null
411
	 */
412
	protected static function unshareItem(array $item, $newParent = null) {
413
		$shareType = (int)$item['share_type'];
414
		$shareWith = null;
415
		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
416
			$shareWith = $item['share_with'];
417
		}
418
419
		// Pass all the vars we have for now, they may be useful
420
		$hookParams = [
421
			'id'            => $item['id'],
422
			'itemType'      => $item['item_type'],
423
			'itemSource'    => $item['item_source'],
424
			'shareType'     => $shareType,
425
			'shareWith'     => $shareWith,
426
			'itemParent'    => $item['parent'],
427
			'uidOwner'      => $item['uid_owner'],
428
		];
429
430
		\OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
431
		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
432
		$deletedShares[] = $hookParams;
433
		$hookParams['deletedShares'] = $deletedShares;
434
		\OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
435
		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
436
			list(, $remote) = Helper::splitUserRemote($item['share_with']);
437
			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
438
		}
439
	}
440
441
	/**
442
	 * Check if resharing is allowed
443
	 * @return boolean true if allowed or false
444
	 *
445
	 * Resharing is allowed by default if not configured
446
	 */
447
	public static function isResharingAllowed() {
448
		if (!isset(self::$isResharingAllowed)) {
449
			if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
450
				self::$isResharingAllowed = true;
451
			} else {
452
				self::$isResharingAllowed = false;
453
			}
454
		}
455
		return self::$isResharingAllowed;
456
	}
457
458
	/**
459
	 * Get a list of collection item types for the specified item type
460
	 * @param string $itemType
461
	 * @return array
462
	 */
463
	private static function getCollectionItemTypes($itemType) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
464
		$collectionTypes = [$itemType];
465
		// Return array if collections were found or the item type is a
466
		// collection itself - collections can be inside collections
467
		if (\count($collectionTypes) > 0) {
468
			return $collectionTypes;
469
		}
470
		return false;
471
	}
472
473
	/**
474
	 * In case a password protected link is not yet authenticated this function will return false
475
	 *
476
	 * @param array $linkItem
477
	 * @return boolean
478
	 */
479
	public static function checkPasswordProtectedShare(array $linkItem) {
480
		if (!isset($linkItem['share_with'])) {
481
			return true;
482
		}
483
		if (!isset($linkItem['share_type'])) {
484
			return true;
485
		}
486
		if (!isset($linkItem['id'])) {
487
			return true;
488
		}
489
490
		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
491
			return true;
492
		}
493
494 View Code Duplication
		if (\OC::$server->getSession()->exists('public_link_authenticated')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
495
			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id']) {
496
			return true;
497
		}
498
499
		return false;
500
	}
501
502
	/**
503
	 * construct select statement
504
	 * @param int $format
505
	 * @param string $uidOwner
506
	 * @return string select statement
507
	 */
508
	private static function createSelectStatement($format, $uidOwner = null) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
509
		$select = '*';
510
		if ($format == self::FORMAT_STATUSES) {
511
			$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
512
		} else {
513
			if (isset($uidOwner)) {
514
				$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
515
					. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
516
			}
517
		}
518
		return $select;
519
	}
520
521
	/**
522
	 * transform db results
523
	 * @param array $row result
524
	 */
525
	private static function transformDBResults(&$row) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
526
		if (isset($row['id'])) {
527
			$row['id'] = (int) $row['id'];
528
		}
529
		if (isset($row['share_type'])) {
530
			$row['share_type'] = (int) $row['share_type'];
531
		}
532
		if (isset($row['parent'])) {
533
			$row['parent'] = (int) $row['parent'];
534
		}
535
		if (isset($row['file_parent'])) {
536
			$row['file_parent'] = (int) $row['file_parent'];
537
		}
538
		if (isset($row['file_source'])) {
539
			$row['file_source'] = (int) $row['file_source'];
540
		}
541
		if (isset($row['permissions'])) {
542
			$row['permissions'] = (int) $row['permissions'];
543
		}
544
		if (isset($row['storage'])) {
545
			$row['storage'] = (int) $row['storage'];
546
		}
547
		if (isset($row['stime'])) {
548
			$row['stime'] = (int) $row['stime'];
549
		}
550
		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
551
			// discard expiration date for non-link shares, which might have been
552
			// set by ancient bugs
553
			$row['expiration'] = null;
554
		}
555
	}
556
557
	/**
558
	 * format result
559
	 * @param array $items result
560
	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
561
	 * @param \OCP\Share_Backend $backend sharing backend
562
	 * @param int $format
563
	 * @param array $parameters additional format parameters
564
	 * @return array format result
565
	 */
566
	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE, $parameters = null) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $backend is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $parameters is not used and could be removed.

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

Loading history...
567
		if ($format === self::FORMAT_NONE) {
568
			return $items;
569
		} elseif ($format === self::FORMAT_STATUSES) {
570
			$statuses = [];
571
			foreach ($items as $item) {
572
				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
573
					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
574
						continue;
575
					}
576
					$statuses[$item[$column]]['link'] = true;
577
				} elseif (!isset($statuses[$item[$column]])) {
578
					$statuses[$item[$column]]['link'] = false;
579
				}
580
				if (!empty($item['file_target'])) {
581
					$statuses[$item[$column]]['path'] = $item['path'];
582
				}
583
			}
584
			return $statuses;
585
		} else {
586
			return null;
587
		}
588
	}
589
590
	/**
591
	 * remove protocol from URL
592
	 *
593
	 * @param string $url
594
	 * @return string
595
	 */
596 View Code Duplication
	public static function removeProtocolFromUrl($url) {
597
		if (\strpos($url, 'https://') === 0) {
598
			return \substr($url, \strlen('https://'));
599
		} elseif (\strpos($url, 'http://') === 0) {
600
			return \substr($url, \strlen('http://'));
601
		}
602
603
		return $url;
604
	}
605
606
	/**
607
	 * try http post first with https and then with http as a fallback
608
	 *
609
	 * @param string $remoteDomain
610
	 * @param string $urlSuffix
611
	 * @param array $fields post parameters
612
	 * @return array
613
	 */
614
	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
615
		$allowHttpFallback = \OC::$server->getConfig()->getSystemValue('sharing.federation.allowHttpFallback', false) === true;
616
		// Always try https first
617
		$protocol = 'https://';
618
		$discoveryManager = new DiscoveryManager(
619
			\OC::$server->getMemCacheFactory(),
620
			\OC::$server->getHTTPClientService()
621
		);
622
623
		$endpoint = $discoveryManager->getShareEndpoint($protocol . $remoteDomain);
624
		// Try HTTPS
625
		$result = \OC::$server->getHTTPHelper()->post(
626
			$protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
627
			$fields);
628
629
		if ($result['success'] === true) {
630
			// Return if https worked
631
			return $result;
632
		} elseif ($result['success'] === false && $allowHttpFallback) {
633
			// If https failed and we can try http - try that
634
			$protocol = 'http://';
635
			$result = \OC::$server->getHTTPHelper()->post(
636
			$protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
637
			$fields);
638
			return $result;
639
		} else {
640
			// Else we just return the failure
641
			return $result;
642
		}
643
	}
644
645
	/**
646
	 * send server-to-server share to remote server
647
	 *
648
	 * @param string $token
649
	 * @param string $shareWith
650
	 * @param string $name
651
	 * @param int $remote_id
652
	 * @param string $owner
653
	 * @return bool
654
	 */
655
	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
656
		list($user, $remote) = Helper::splitUserRemote($shareWith);
657
658
		if ($user && $remote) {
659
			$url = $remote;
660
661
			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
662
663
			$fields = [
664
				'shareWith' => $user,
665
				'token' => $token,
666
				'name' => $name,
667
				'remoteId' => $remote_id,
668
				'owner' => $owner,
669
				'remote' => $local,
670
			];
671
672
			$url = self::removeProtocolFromUrl($url);
673
			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
674
			$status = \json_decode($result['result'], true);
675
676
			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
677
				\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
678
				return true;
679
			}
680
		}
681
682
		return false;
683
	}
684
685
	/**
686
	 * send server-to-server unshare to remote server
687
	 *
688
	 * @param string $remote url
689
	 * @param int $id share id
690
	 * @param string $token
691
	 * @return bool
692
	 */
693
	private static function sendRemoteUnshare($remote, $id, $token) {
694
		$url = \rtrim($remote, '/');
695
		$fields = ['token' => $token, 'format' => 'json'];
696
		$url = self::removeProtocolFromUrl($url);
697
		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
698
		$status = \json_decode($result['result'], true);
699
700
		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
701
	}
702
703
	/**
704
	 * @param IConfig $config
705
	 * @return bool
706
	 */
707
	public static function enforcePassword(IConfig $config) {
708
		$enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
709
		return ($enforcePassword === "yes") ? true : false;
710
	}
711
712
	/**
713
	 * Get all share entries, including non-unique group items
714
	 *
715
	 * @param string $owner
716
	 * @return array
717
	 */
718
	public static function getAllSharesForOwner($owner) {
719
		$query = 'SELECT * FROM `*PREFIX*share` WHERE `uid_owner` = ?';
720
		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$owner]);
721
		return $result->fetchAll();
722
	}
723
724
	/**
725
	 * Get all share entries, including non-unique group items for a file
726
	 *
727
	 * @param int $id
728
	 * @return array
729
	 */
730
	public static function getAllSharesForFileId($id) {
731
		$query = 'SELECT * FROM `*PREFIX*share` WHERE `file_source` = ?';
732
		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$id]);
733
		return $result->fetchAll();
734
	}
735
736
	/**
737
	 * @param string $password
738
	 * @throws \Exception
739
	 */
740
	private static function verifyPassword($password) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
741
		$accepted = true;
742
		$message = '';
743
		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
744
			'password' => $password,
745
			'accepted' => &$accepted,
746
			'message' => &$message
747
		]);
748
749
		if (!$accepted) {
750
			throw new \Exception($message);
751
		}
752
753
		\OC::$server->getEventDispatcher()->dispatch(
754
			'OCP\Share::validatePassword',
755
			new GenericEvent(null, ['password' => $password])
756
		);
757
	}
758
759
	/**
760
	 * @param $user
761
	 * @return Group[]
762
	 */
763
	private static function getGroupsForUser($user) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
764
		$groups = \OC::$server->getGroupManager()->getUserIdGroups($user, 'sharing');
765
		return \array_values(\array_map(function (Group $g) {
766
			return $g->getGID();
767
		}, $groups));
768
	}
769
770
	/**
771
	 * @param $group
772
	 * @return mixed
773
	 */
774
	private static function usersInGroup($group) {
775
		$g = \OC::$server->getGroupManager()->get($group);
776
		if ($g === null) {
777
			return [];
778
		}
779
		return \array_values(\array_map(function (IUser $u) {
780
			return $u->getUID();
781
		}, $g->getUsers()));
782
	}
783
}
784