Completed
Push — master ( b4df57...e6895c )
by Lukas
26s
created

Helper::getShareFolder()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 21
Code Lines 13

Duplication

Lines 10
Ratio 47.62 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 13
c 1
b 0
f 0
nc 4
nop 1
dl 10
loc 21
rs 8.7624
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', 'post_rename', '\OCA\Files_Sharing\Updater', 'renameHook');
40
		\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
41
		\OCP\Util::connectHook('OC_Appconfig', 'post_set_value', '\OCA\Files_Sharing\Maintainer', 'configChangeHook');
42
43
		\OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser');
44
	}
45
46
	/**
47
	 * Sets up the filesystem and user for public sharing
48
	 * @param string $token string share token
49
	 * @param string $relativePath optional path relative to the share
50
	 * @param string $password optional password
51
	 * @return array
52
	 */
53
	public static function setupFromToken($token, $relativePath = null, $password = null) {
54
		\OC_User::setIncognitoMode(true);
55
56
		$linkItem = \OCP\Share::getShareByToken($token, !$password);
57 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...
58
			\OC_Response::setStatus(404);
59
			\OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
60
			exit;
61
		}
62
63 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...
64
			\OC_Response::setStatus(500);
65
			\OCP\Util::writeLog('core-preview', 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")', \OCP\Util::WARN);
66
			exit;
67
		}
68
69
		$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 56 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...
70
		$path = null;
71
		if (isset($rootLinkItem['uid_owner'])) {
72
			\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...
73
			\OC_Util::tearDownFS();
74
			\OC_Util::setupFS($rootLinkItem['uid_owner']);
75
		}
76
77
		try {
78
			$path = Filesystem::getPath($linkItem['file_source']);
79
		} catch (NotFoundException $e) {
80
			\OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
81
			\OC_Response::setStatus(404);
82
			\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...
83
			exit();
84
		}
85
86
		if (!isset($linkItem['item_type'])) {
87
			\OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
88
			\OC_Response::setStatus(404);
89
			\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...
90
			exit();
91
		}
92
93
		if (isset($linkItem['share_with']) && (int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
94
			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 56 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...
95
				\OC_Response::setStatus(403);
96
				\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...
97
				exit();
98
			}
99
		}
100
101
		$basePath = $path;
102
103
		if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
104
			$path .= Filesystem::normalizePath($relativePath);
105
		}
106
107
		return array(
108
			'linkItem' => $linkItem,
109
			'basePath' => $basePath,
110
			'realPath' => $path
111
		);
112
	}
113
114
	/**
115
	 * Authenticate link item with the given password
116
	 * or with the session if no password was given.
117
	 * @param array $linkItem link item array
118
	 * @param string $password optional password
119
	 *
120
	 * @return boolean true if authorized, false otherwise
121
	 */
122
	public static function authenticate($linkItem, $password = null) {
123
		if ($password !== null) {
124
			if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {
125
				// Check Password
126
				$newHash = '';
127
				if(\OC::$server->getHasher()->verify($password, $linkItem['share_with'], $newHash)) {
128
					// Save item id in session for future requests
129
					\OC::$server->getSession()->set('public_link_authenticated', (string) $linkItem['id']);
130
131
					/**
132
					 * FIXME: Migrate old hashes to new hash format
133
					 * Due to the fact that there is no reasonable functionality to update the password
134
					 * of an existing share no migration is yet performed there.
135
					 * The only possibility is to update the existing share which will result in a new
136
					 * share ID and is a major hack.
137
					 *
138
					 * In the future the migration should be performed once there is a proper method
139
					 * to update the share's password. (for example `$share->updatePassword($password)`
140
					 *
141
					 * @link https://github.com/owncloud/core/issues/10671
142
					 */
143
					if(!empty($newHash)) {
144
145
					}
146
				} else {
147
					return false;
148
				}
149
			} else {
150
				\OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
151
					.' for share id '.$linkItem['id'], \OCP\Util::ERROR);
152
				return false;
153
			}
154
155
		}
156 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...
157
			// not authenticated ?
158
			if ( ! \OC::$server->getSession()->exists('public_link_authenticated')
159
				|| \OC::$server->getSession()->get('public_link_authenticated') !== (string)$linkItem['id']) {
160
				return false;
161
			}
162
		}
163
		return true;
164
	}
165
166
	public static function getSharesFromItem($target) {
167
		$result = array();
168
		$owner = Filesystem::getOwner($target);
169
		Filesystem::initMountPoints($owner);
170
		$info = Filesystem::getFileInfo($target);
171
		$ownerView = new View('/'.$owner.'/files');
172
		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...
173
			$path = $ownerView->getPath($info['fileid']);
174
		} else {
175
			$path = $target;
176
		}
177
178
179
		$ids = array();
180
		while ($path !== dirname($path)) {
181
			$info = $ownerView->getFileInfo($path);
182
			if ($info instanceof \OC\Files\FileInfo) {
183
				$ids[] = $info['fileid'];
184
			} else {
185
				\OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
186
			}
187
			$path = dirname($path);
188
		}
189
190
		if (!empty($ids)) {
191
192
			$idList = array_chunk($ids, 99, true);
193
194
			foreach ($idList as $subList) {
195
				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
196
				$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...
197
				$r = $query->execute();
198
				$result = array_merge($result, $r->fetchAll());
199
			}
200
		}
201
202
		return $result;
203
	}
204
205
	/**
206
	 * get the UID of the owner of the file and the path to the file relative to
207
	 * owners files folder
208
	 *
209
	 * @param $filename
210
	 * @return array
211
	 * @throws \OC\User\NoUserException
212
	 */
213 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...
214
		$uid = Filesystem::getOwner($filename);
215
		$userManager = \OC::$server->getUserManager();
216
		// if the user with the UID doesn't exists, e.g. because the UID points
217
		// to a remote user with a federated cloud ID we use the current logged-in
218
		// user. We need a valid local user to create the share
219
		if (!$userManager->userExists($uid)) {
220
			$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...
221
		}
222
		Filesystem::initMountPoints($uid);
223
		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...
224
			$info = Filesystem::getFileInfo($filename);
225
			$ownerView = new View('/'.$uid.'/files');
226
			try {
227
				$filename = $ownerView->getPath($info['fileid']);
228
			} catch (NotFoundException $e) {
229
				$filename = null;
230
			}
231
		}
232
		return [$uid, $filename];
233
	}
234
235
	/**
236
	 * Format a path to be relative to the /user/files/ directory
237
	 * @param string $path the absolute path
238
	 * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
239
	 */
240
	public static function stripUserFilesPath($path) {
241
		$trimmed = ltrim($path, '/');
242
		$split = explode('/', $trimmed);
243
244
		// it is not a file relative to data/user/files
245
		if (count($split) < 3 || $split[1] !== 'files') {
246
			return false;
247
		}
248
249
		$sliced = array_slice($split, 2);
250
		$relPath = implode('/', $sliced);
251
252
		return $relPath;
253
	}
254
255
	/**
256
	 * check if file name already exists and generate unique target
257
	 *
258
	 * @param string $path
259
	 * @param array $excludeList
260
	 * @param View $view
261
	 * @return string $path
262
	 */
263
	public static function generateUniqueTarget($path, $excludeList, $view) {
264
		$pathinfo = pathinfo($path);
265
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
266
		$name = $pathinfo['filename'];
267
		$dir = $pathinfo['dirname'];
268
		$i = 2;
269 View Code Duplication
		while ($view->file_exists($path) || in_array($path, $excludeList)) {
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...
270
			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
271
			$i++;
272
		}
273
274
		return $path;
275
	}
276
277
	/**
278
	 * get default share folder
279
	 *
280
	 * @param \OC\Files\View
281
	 * @return string
282
	 */
283
	public static function getShareFolder($view = null) {
284
		if ($view === null) {
285
			$view = Filesystem::getView();
286
		}
287
		$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
288
		$shareFolder = Filesystem::normalizePath($shareFolder);
289
290 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...
291
			$dir = '';
292
			$subdirs = explode('/', $shareFolder);
293
			foreach ($subdirs as $subdir) {
294
				$dir = $dir . '/' . $subdir;
295
				if (!$view->is_dir($dir)) {
296
					$view->mkdir($dir);
297
				}
298
			}
299
		}
300
301
		return $shareFolder;
302
303
	}
304
305
	/**
306
	 * set default share folder
307
	 *
308
	 * @param string $shareFolder
309
	 */
310
	public static function setShareFolder($shareFolder) {
311
		\OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
312
	}
313
314
}
315