Completed
Push — stable9 ( 485cb1...e094cf )
by Lukas
26:41 queued 26:23
created

Helper::stripUserFilesPath()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 2
nop 1
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Björn Schießle <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
namespace OCA\Files_Sharing;
31
32
use OC\Files\Filesystem;
33
use OC\Files\View;
34
use OCP\Files\NotFoundException;
35
use OCP\User;
36
37
class Helper {
38
39
	public static function registerHooks() {
40
		\OCP\Util::connectHook('OC_Filesystem', 'delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');
41
		\OCP\Util::connectHook('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Shared_Updater', 'renameHook');
42
		\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
43
		\OCP\Util::connectHook('OC_Appconfig', 'post_set_value', '\OCA\Files\Share\Maintainer', 'configChangeHook');
44
45
		\OCP\Util::connectHook('OCP\Share', 'post_shared', '\OC\Files\Cache\Shared_Updater', 'postShareHook');
46
		\OCP\Util::connectHook('OCP\Share', 'post_unshare', '\OC\Files\Cache\Shared_Updater', 'postUnshareHook');
47
		\OCP\Util::connectHook('OCP\Share', 'post_unshareFromSelf', '\OC\Files\Cache\Shared_Updater', 'postUnshareFromSelfHook');
48
49
		\OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser');
50
	}
51
52
	/**
53
	 * Sets up the filesystem and user for public sharing
54
	 * @param string $token string share token
55
	 * @param string $relativePath optional path relative to the share
56
	 * @param string $password optional password
57
	 * @return array
58
	 */
59
	public static function setupFromToken($token, $relativePath = null, $password = null) {
60
		\OC_User::setIncognitoMode(true);
61
62
		$linkItem = \OCP\Share::getShareByToken($token, !$password);
63 View Code Duplication
		if($linkItem === false || ($linkItem['item_type'] !== 'file' && $linkItem['item_type'] !== 'folder')) {
64
			\OC_Response::setStatus(404);
65
			\OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
66
			exit;
67
		}
68
69 View Code Duplication
		if(!isset($linkItem['uid_owner']) || !isset($linkItem['file_source'])) {
70
			\OC_Response::setStatus(500);
71
			\OCP\Util::writeLog('core-preview', 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")', \OCP\Util::WARN);
72
			exit;
73
		}
74
75
		$rootLinkItem = \OCP\Share::resolveReShare($linkItem);
0 ignored issues
show
Bug introduced by
It seems like $linkItem defined by \OCP\Share::getShareByToken($token, !$password) on line 62 can also be of type boolean; however, OCP\Share::resolveReShare() does only seem to accept array, 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...
76
		$path = null;
77
		if (isset($rootLinkItem['uid_owner'])) {
78
			\OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\JSON::checkUserExists() has been deprecated with message: 8.1.0 Use a AppFramework JSONResponse instead

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...
79
			\OC_Util::tearDownFS();
80
			\OC_Util::setupFS($rootLinkItem['uid_owner']);
81
		}
82
83
		try {
84
			$path = Filesystem::getPath($linkItem['file_source']);
85
		} catch (NotFoundException $e) {
86
			\OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
87
			\OC_Response::setStatus(404);
88
			\OCP\JSON::error(array('success' => false));
0 ignored issues
show
Deprecated Code introduced by
The method OCP\JSON::error() has been deprecated with message: 8.1.0 Use a AppFramework JSONResponse instead

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...
89
			exit();
90
		}
91
92
		if (!isset($linkItem['item_type'])) {
93
			\OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
94
			\OC_Response::setStatus(404);
95
			\OCP\JSON::error(array('success' => false));
0 ignored issues
show
Deprecated Code introduced by
The method OCP\JSON::error() has been deprecated with message: 8.1.0 Use a AppFramework JSONResponse instead

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...
96
			exit();
97
		}
98
99
		if (isset($linkItem['share_with']) && (int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
100
			if (!self::authenticate($linkItem, $password)) {
0 ignored issues
show
Bug introduced by
It seems like $linkItem defined by \OCP\Share::getShareByToken($token, !$password) on line 62 can also be of type boolean; however, OCA\Files_Sharing\Helper::authenticate() does only seem to accept array, 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...
101
				\OC_Response::setStatus(403);
102
				\OCP\JSON::error(array('success' => false));
0 ignored issues
show
Deprecated Code introduced by
The method OCP\JSON::error() has been deprecated with message: 8.1.0 Use a AppFramework JSONResponse instead

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...
103
				exit();
104
			}
105
		}
106
107
		$basePath = $path;
108
109
		if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
110
			$path .= Filesystem::normalizePath($relativePath);
111
		}
112
113
		return array(
114
			'linkItem' => $linkItem,
115
			'basePath' => $basePath,
116
			'realPath' => $path
117
		);
118
	}
119
120
	/**
121
	 * Authenticate link item with the given password
122
	 * or with the session if no password was given.
123
	 * @param array $linkItem link item array
124
	 * @param string $password optional password
125
	 *
126
	 * @return boolean true if authorized, false otherwise
127
	 */
128
	public static function authenticate($linkItem, $password = null) {
129
		if ($password !== null) {
130
			if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {
131
				// Check Password
132
				$newHash = '';
133
				if(\OC::$server->getHasher()->verify($password, $linkItem['share_with'], $newHash)) {
134
					// Save item id in session for future requests
135
					\OC::$server->getSession()->set('public_link_authenticated', (string) $linkItem['id']);
136
137
					/**
138
					 * FIXME: Migrate old hashes to new hash format
139
					 * Due to the fact that there is no reasonable functionality to update the password
140
					 * of an existing share no migration is yet performed there.
141
					 * The only possibility is to update the existing share which will result in a new
142
					 * share ID and is a major hack.
143
					 *
144
					 * In the future the migration should be performed once there is a proper method
145
					 * to update the share's password. (for example `$share->updatePassword($password)`
146
					 *
147
					 * @link https://github.com/owncloud/core/issues/10671
148
					 */
149
					if(!empty($newHash)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
150
151
					}
152
				} else {
153
					return false;
154
				}
155
			} else {
156
				\OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
157
					.' for share id '.$linkItem['id'], \OCP\Util::ERROR);
158
				return false;
159
			}
160
161
		}
162 View Code Duplication
		else {
163
			// not authenticated ?
164
			if ( ! \OC::$server->getSession()->exists('public_link_authenticated')
165
				|| \OC::$server->getSession()->get('public_link_authenticated') !== (string)$linkItem['id']) {
166
				return false;
167
			}
168
		}
169
		return true;
170
	}
171
172
	public static function getSharesFromItem($target) {
173
		$result = array();
174
		$owner = Filesystem::getOwner($target);
175
		Filesystem::initMountPoints($owner);
176
		$info = Filesystem::getFileInfo($target);
177
		$ownerView = new View('/'.$owner.'/files');
178
		if ( $owner != 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...
179
			$path = $ownerView->getPath($info['fileid']);
180
		} else {
181
			$path = $target;
182
		}
183
184
185
		$ids = array();
186
		while ($path !== dirname($path)) {
187
			$info = $ownerView->getFileInfo($path);
188
			if ($info instanceof \OC\Files\FileInfo) {
189
				$ids[] = $info['fileid'];
190
			} else {
191
				\OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
192
			}
193
			$path = dirname($path);
194
		}
195
196
		if (!empty($ids)) {
197
198
			$idList = array_chunk($ids, 99, true);
199
200
			foreach ($idList as $subList) {
201
				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
202
				$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...
203
				$r = $query->execute();
204
				$result = array_merge($result, $r->fetchAll());
205
			}
206
		}
207
208
		return $result;
209
	}
210
211
	/**
212
	 * get the UID of the owner of the file and the path to the file relative to
213
	 * owners files folder
214
	 *
215
	 * @param $filename
216
	 * @return array
217
	 * @throws \OC\User\NoUserException
218
	 */
219 View Code Duplication
	public static function getUidAndFilename($filename) {
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...
220
		$uid = Filesystem::getOwner($filename);
221
		$userManager = \OC::$server->getUserManager();
222
		// if the user with the UID doesn't exists, e.g. because the UID points
223
		// to a remote user with a federated cloud ID we use the current logged-in
224
		// user. We need a valid local user to create the share
225
		if (!$userManager->userExists($uid)) {
226
			$uid = 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...
227
		}
228
		Filesystem::initMountPoints($uid);
229
		if ( $uid != 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...
230
			$info = Filesystem::getFileInfo($filename);
231
			$ownerView = new View('/'.$uid.'/files');
232
			try {
233
				$filename = $ownerView->getPath($info['fileid']);
234
			} catch (NotFoundException $e) {
235
				$filename = null;
236
			}
237
		}
238
		return [$uid, $filename];
239
	}
240
241
	/**
242
	 * Format a path to be relative to the /user/files/ directory
243
	 * @param string $path the absolute path
244
	 * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
245
	 */
246
	public static function stripUserFilesPath($path) {
247
		$trimmed = ltrim($path, '/');
248
		$split = explode('/', $trimmed);
249
250
		// it is not a file relative to data/user/files
251
		if (count($split) < 3 || $split[1] !== 'files') {
252
			return false;
253
		}
254
255
		$sliced = array_slice($split, 2);
256
		$relPath = implode('/', $sliced);
257
258
		return $relPath;
259
	}
260
261
	/**
262
	 * check if file name already exists and generate unique target
263
	 *
264
	 * @param string $path
265
	 * @param array $excludeList
266
	 * @param View $view
267
	 * @return string $path
268
	 */
269
	public static function generateUniqueTarget($path, $excludeList, $view) {
270
		$pathinfo = pathinfo($path);
271
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
272
		$name = $pathinfo['filename'];
273
		$dir = $pathinfo['dirname'];
274
		$i = 2;
275 View Code Duplication
		while ($view->file_exists($path) || in_array($path, $excludeList)) {
276
			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
277
			$i++;
278
		}
279
280
		return $path;
281
	}
282
283
	/**
284
	 * allow users from other ownCloud instances to mount public links share by this instance
285
	 * @return bool
286
	 */
287
	public static function isOutgoingServer2serverShareEnabled() {
288
		$appConfig = \OC::$server->getAppConfig();
289
		$result = $appConfig->getValue('files_sharing', 'outgoing_server2server_share_enabled', '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...
290
		return ($result === 'yes') ? true : false;
291
	}
292
293
	/**
294
	 * allow user to mount public links from onther ownClouds
295
	 * @return bool
296
	 */
297
	public static function isIncomingServer2serverShareEnabled() {
298
		$appConfig = \OC::$server->getAppConfig();
299
		$result = $appConfig->getValue('files_sharing', 'incoming_server2server_share_enabled', '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...
300
		return ($result === 'yes') ? true : false;
301
	}
302
303
	/**
304
	 * get default share folder
305
	 *
306
	 * @param \OC\Files\View
307
	 * @return string
308
	 */
309
	public static function getShareFolder($view = null) {
310
		if ($view === null) {
311
			$view = Filesystem::getView();
312
		}
313
		$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
314
		$shareFolder = Filesystem::normalizePath($shareFolder);
315
316 View Code Duplication
		if (!$view->file_exists($shareFolder)) {
317
			$dir = '';
318
			$subdirs = explode('/', $shareFolder);
319
			foreach ($subdirs as $subdir) {
320
				$dir = $dir . '/' . $subdir;
321
				if (!$view->is_dir($dir)) {
322
					$view->mkdir($dir);
323
				}
324
			}
325
		}
326
327
		return $shareFolder;
328
329
	}
330
331
	/**
332
	 * set default share folder
333
	 *
334
	 * @param string $shareFolder
335
	 */
336
	public static function setShareFolder($shareFolder) {
337
		\OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
338
	}
339
340
}
341