Completed
Push — stable9 ( 4ca096...bbe16d )
by Morris
28s
created

Helper   C

Complexity

Total Complexity 49

Size/Duplication

Total Lines 304
Duplicated Lines 15.79 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 48
loc 304
rs 5.1442
wmc 49
lcom 1
cbo 18

11 Methods

Rating   Name   Duplication   Size   Complexity  
A registerHooks() 0 12 1
C setupFromToken() 10 60 14
C authenticate() 7 43 7
B getSharesFromItem() 0 38 6
A getUidAndFilename() 21 21 4
A stripUserFilesPath() 0 14 3
A generateUniqueTarget() 0 13 4
A isOutgoingServer2serverShareEnabled() 0 5 2
A isIncomingServer2serverShareEnabled() 0 5 2
B getShareFolder() 10 21 5
A setShareFolder() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Helper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Helper, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @author Bart Visscher <[email protected]>
4
 * @author Björn Schießle <[email protected]>
5
 * @author Joas Schilling <[email protected]>
6
 * @author Jörn Friedrich Dreyer <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Robin Appelman <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 * @author Vincent Petry <[email protected]>
12
 *
13
 * @copyright Copyright (c) 2016, ownCloud, Inc.
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
namespace OCA\Files_Sharing;
30
31
use OC\Files\Filesystem;
32
use OC\Files\View;
33
use OCP\Files\NotFoundException;
34
use OCP\User;
35
36
class Helper {
37
38
	public static function registerHooks() {
39
		\OCP\Util::connectHook('OC_Filesystem', 'delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');
40
		\OCP\Util::connectHook('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Shared_Updater', 'renameHook');
41
		\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
42
		\OCP\Util::connectHook('OC_Appconfig', 'post_set_value', '\OCA\Files\Share\Maintainer', 'configChangeHook');
43
44
		\OCP\Util::connectHook('OCP\Share', 'post_shared', '\OC\Files\Cache\Shared_Updater', 'postShareHook');
45
		\OCP\Util::connectHook('OCP\Share', 'post_unshare', '\OC\Files\Cache\Shared_Updater', 'postUnshareHook');
46
		\OCP\Util::connectHook('OCP\Share', 'post_unshareFromSelf', '\OC\Files\Cache\Shared_Updater', 'postUnshareFromSelfHook');
47
48
		\OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser');
49
	}
50
51
	/**
52
	 * Sets up the filesystem and user for public sharing
53
	 * @param string $token string share token
54
	 * @param string $relativePath optional path relative to the share
55
	 * @param string $password optional password
56
	 * @return array
57
	 */
58
	public static function setupFromToken($token, $relativePath = null, $password = null) {
59
		\OC_User::setIncognitoMode(true);
60
61
		$linkItem = \OCP\Share::getShareByToken($token, !$password);
62 View Code Duplication
		if($linkItem === false || ($linkItem['item_type'] !== 'file' && $linkItem['item_type'] !== 'folder')) {
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...
63
			\OC_Response::setStatus(404);
64
			\OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
65
			exit;
66
		}
67
68 View Code Duplication
		if(!isset($linkItem['uid_owner']) || !isset($linkItem['file_source'])) {
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...
69
			\OC_Response::setStatus(500);
70
			\OCP\Util::writeLog('core-preview', 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")', \OCP\Util::WARN);
71
			exit;
72
		}
73
74
		$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 61 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...
75
		$path = null;
76
		if (isset($rootLinkItem['uid_owner'])) {
77
			\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...
78
			\OC_Util::tearDownFS();
79
			\OC_Util::setupFS($rootLinkItem['uid_owner']);
80
		}
81
82
		try {
83
			$path = Filesystem::getPath($linkItem['file_source']);
84
		} catch (NotFoundException $e) {
85
			\OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
86
			\OC_Response::setStatus(404);
87
			\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...
88
			exit();
89
		}
90
91
		if (!isset($linkItem['item_type'])) {
92
			\OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
93
			\OC_Response::setStatus(404);
94
			\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...
95
			exit();
96
		}
97
98
		if (isset($linkItem['share_with']) && (int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
99
			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 61 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...
100
				\OC_Response::setStatus(403);
101
				\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...
102
				exit();
103
			}
104
		}
105
106
		$basePath = $path;
107
108
		if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
109
			$path .= Filesystem::normalizePath($relativePath);
110
		}
111
112
		return array(
113
			'linkItem' => $linkItem,
114
			'basePath' => $basePath,
115
			'realPath' => $path
116
		);
117
	}
118
119
	/**
120
	 * Authenticate link item with the given password
121
	 * or with the session if no password was given.
122
	 * @param array $linkItem link item array
123
	 * @param string $password optional password
124
	 *
125
	 * @return boolean true if authorized, false otherwise
126
	 */
127
	public static function authenticate($linkItem, $password = null) {
128
		if ($password !== null) {
129
			if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {
130
				// Check Password
131
				$newHash = '';
132
				if(\OC::$server->getHasher()->verify($password, $linkItem['share_with'], $newHash)) {
133
					// Save item id in session for future requests
134
					\OC::$server->getSession()->set('public_link_authenticated', (string) $linkItem['id']);
135
136
					/**
137
					 * FIXME: Migrate old hashes to new hash format
138
					 * Due to the fact that there is no reasonable functionality to update the password
139
					 * of an existing share no migration is yet performed there.
140
					 * The only possibility is to update the existing share which will result in a new
141
					 * share ID and is a major hack.
142
					 *
143
					 * In the future the migration should be performed once there is a proper method
144
					 * to update the share's password. (for example `$share->updatePassword($password)`
145
					 *
146
					 * @link https://github.com/owncloud/core/issues/10671
147
					 */
148
					if(!empty($newHash)) {
149
150
					}
151
				} else {
152
					return false;
153
				}
154
			} else {
155
				\OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
156
					.' for share id '.$linkItem['id'], \OCP\Util::ERROR);
157
				return false;
158
			}
159
160
		}
161 View Code Duplication
		else {
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...
162
			// not authenticated ?
163
			if ( ! \OC::$server->getSession()->exists('public_link_authenticated')
164
				|| \OC::$server->getSession()->get('public_link_authenticated') !== (string)$linkItem['id']) {
165
				return false;
166
			}
167
		}
168
		return true;
169
	}
170
171
	public static function getSharesFromItem($target) {
172
		$result = array();
173
		$owner = Filesystem::getOwner($target);
174
		Filesystem::initMountPoints($owner);
175
		$info = Filesystem::getFileInfo($target);
176
		$ownerView = new View('/'.$owner.'/files');
177
		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...
178
			$path = $ownerView->getPath($info['fileid']);
179
		} else {
180
			$path = $target;
181
		}
182
183
184
		$ids = array();
185
		while ($path !== dirname($path)) {
186
			$info = $ownerView->getFileInfo($path);
187
			if ($info instanceof \OC\Files\FileInfo) {
188
				$ids[] = $info['fileid'];
189
			} else {
190
				\OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
191
			}
192
			$path = dirname($path);
193
		}
194
195
		if (!empty($ids)) {
196
197
			$idList = array_chunk($ids, 99, true);
198
199
			foreach ($idList as $subList) {
200
				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
201
				$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...
202
				$r = $query->execute();
203
				$result = array_merge($result, $r->fetchAll());
204
			}
205
		}
206
207
		return $result;
208
	}
209
210
	/**
211
	 * get the UID of the owner of the file and the path to the file relative to
212
	 * owners files folder
213
	 *
214
	 * @param $filename
215
	 * @return array
216
	 * @throws \OC\User\NoUserException
217
	 */
218 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...
219
		$uid = Filesystem::getOwner($filename);
220
		$userManager = \OC::$server->getUserManager();
221
		// if the user with the UID doesn't exists, e.g. because the UID points
222
		// to a remote user with a federated cloud ID we use the current logged-in
223
		// user. We need a valid local user to create the share
224
		if (!$userManager->userExists($uid)) {
225
			$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...
226
		}
227
		Filesystem::initMountPoints($uid);
228
		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...
229
			$info = Filesystem::getFileInfo($filename);
230
			$ownerView = new View('/'.$uid.'/files');
231
			try {
232
				$filename = $ownerView->getPath($info['fileid']);
233
			} catch (NotFoundException $e) {
234
				$filename = null;
235
			}
236
		}
237
		return [$uid, $filename];
238
	}
239
240
	/**
241
	 * Format a path to be relative to the /user/files/ directory
242
	 * @param string $path the absolute path
243
	 * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
244
	 */
245
	public static function stripUserFilesPath($path) {
246
		$trimmed = ltrim($path, '/');
247
		$split = explode('/', $trimmed);
248
249
		// it is not a file relative to data/user/files
250
		if (count($split) < 3 || $split[1] !== 'files') {
251
			return false;
252
		}
253
254
		$sliced = array_slice($split, 2);
255
		$relPath = implode('/', $sliced);
256
257
		return $relPath;
258
	}
259
260
	/**
261
	 * check if file name already exists and generate unique target
262
	 *
263
	 * @param string $path
264
	 * @param array $excludeList
265
	 * @param View $view
266
	 * @return string $path
267
	 */
268
	public static function generateUniqueTarget($path, $excludeList, $view) {
269
		$pathinfo = pathinfo($path);
270
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
271
		$name = $pathinfo['filename'];
272
		$dir = $pathinfo['dirname'];
273
		$i = 2;
274
		while ($view->file_exists($path) || in_array($path, $excludeList)) {
275
			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
276
			$i++;
277
		}
278
279
		return $path;
280
	}
281
282
	/**
283
	 * allow users from other ownCloud instances to mount public links share by this instance
284
	 * @return bool
285
	 */
286
	public static function isOutgoingServer2serverShareEnabled() {
287
		$appConfig = \OC::$server->getAppConfig();
288
		$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...
289
		return ($result === 'yes') ? true : false;
290
	}
291
292
	/**
293
	 * allow user to mount public links from onther ownClouds
294
	 * @return bool
295
	 */
296
	public static function isIncomingServer2serverShareEnabled() {
297
		$appConfig = \OC::$server->getAppConfig();
298
		$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...
299
		return ($result === 'yes') ? true : false;
300
	}
301
302
	/**
303
	 * get default share folder
304
	 *
305
	 * @param \OC\Files\View
306
	 * @return string
307
	 */
308
	public static function getShareFolder($view = null) {
309
		if ($view === null) {
310
			$view = Filesystem::getView();
311
		}
312
		$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
313
		$shareFolder = Filesystem::normalizePath($shareFolder);
314
315 View Code Duplication
		if (!$view->file_exists($shareFolder)) {
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...
316
			$dir = '';
317
			$subdirs = explode('/', $shareFolder);
318
			foreach ($subdirs as $subdir) {
319
				$dir = $dir . '/' . $subdir;
320
				if (!$view->is_dir($dir)) {
321
					$view->mkdir($dir);
322
				}
323
			}
324
		}
325
326
		return $shareFolder;
327
328
	}
329
330
	/**
331
	 * set default share folder
332
	 *
333
	 * @param string $shareFolder
334
	 */
335
	public static function setShareFolder($shareFolder) {
336
		\OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
337
	}
338
339
}
340