Completed
Push — master ( 68735c...ea470f )
by Björn
11:25
created

MountPublicLinkController   C

Complexity

Total Complexity 24

Size/Duplication

Total Lines 278
Duplicated Lines 7.19 %

Coupling/Cohesion

Components 1
Dependencies 24

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
c 2
b 0
f 0
lcom 1
cbo 24
dl 20
loc 278
rs 5.238

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 20 20 1
C createFederatedShare() 0 37 7
B askForFederatedShare() 0 42 6
D legacyMountPublicLink() 0 98 10

How to fix   Duplicated Code   

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:

1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2016, ownCloud, Inc.
6
 * @copyright Copyright (c) 2016, Björn Schießle <[email protected]>
7
 *
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
25
namespace OCA\FederatedFileSharing\Controller;
26
27
use OC\HintException;
28
use OCA\FederatedFileSharing\AddressHandler;
29
use OCA\FederatedFileSharing\FederatedShareProvider;
30
use OCP\AppFramework\Controller;
31
use OCP\AppFramework\Http;
32
use OCP\AppFramework\Http\JSONResponse;
33
use OCP\Http\Client\IClientService;
34
use OCP\IL10N;
35
use OCP\IRequest;
36
use OCP\ISession;
37
use OCP\IUserSession;
38
use OCP\Share\IManager;
39
40
/**
41
 * Class MountPublicLinkController
42
 *
43
 * convert public links to federated shares
44
 *
45
 * @package OCA\FederatedFileSharing\Controller
46
 */
47
class MountPublicLinkController extends Controller {
48
49
	/** @var FederatedShareProvider */
50
	private $federatedShareProvider;
51
52
	/** @var AddressHandler */
53
	private $addressHandler;
54
55
	/** @var IManager  */
56
	private $shareManager;
57
58
	/** @var  ISession */
59
	private $session;
60
61
	/** @var IL10N */
62
	private $l;
63
64
	/** @var IUserSession */
65
	private $userSession;
66
67
	/** @var IClientService */
68
	private $clientService;
69
70
	/**
71
	 * MountPublicLinkController constructor.
72
	 *
73
	 * @param string $appName
74
	 * @param IRequest $request
75
	 * @param FederatedShareProvider $federatedShareProvider
76
	 * @param IManager $shareManager
77
	 * @param AddressHandler $addressHandler
78
	 * @param ISession $session
79
	 * @param IL10N $l
80
	 * @param IUserSession $userSession
81
	 * @param IClientService $clientService
82
	 */
83 View Code Duplication
	public function __construct($appName,
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...
84
								IRequest $request,
85
								FederatedShareProvider $federatedShareProvider,
86
								IManager $shareManager,
87
								AddressHandler $addressHandler,
88
								ISession $session,
89
								IL10N $l,
90
								IUserSession $userSession,
91
								IClientService $clientService
92
	) {
93
		parent::__construct($appName, $request);
94
95
		$this->federatedShareProvider = $federatedShareProvider;
96
		$this->shareManager = $shareManager;
97
		$this->addressHandler = $addressHandler;
98
		$this->session = $session;
99
		$this->l = $l;
100
		$this->userSession = $userSession;
101
		$this->clientService = $clientService;
102
	}
103
104
	/**
105
	 * send federated share to a user of a public link
106
	 *
107
	 * @NoCSRFRequired
108
	 * @PublicPage
109
	 *
110
	 * @param string $shareWith
111
	 * @param string $token
112
	 * @param string $password
113
	 * @return JSONResponse
114
	 */
115
	public function createFederatedShare($shareWith, $token, $password = '') {
116
117
		if (!$this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) {
118
			return new JSONResponse(
119
				['message' => 'This server doesn\'t support outgoing federated shares'],
120
				Http::STATUS_BAD_REQUEST
121
			);
122
		}
123
124
		try {
125
			list(, $server) = $this->addressHandler->splitUserRemote($shareWith);
126
			$share = $this->shareManager->getShareByToken($token);
127
		} catch (HintException $e) {
128
			return new JSONResponse(['message' => $e->getHint()], Http::STATUS_BAD_REQUEST);
129
		}
130
131
		// make sure that user is authenticated in case of a password protected link
132
		$storedPassword = $share->getPassword();
133
		$authenticated = $this->session->get('public_link_authenticated') === $share->getId() ||
134
			$this->shareManager->checkPassword($share, $password);
135
		if (!empty($storedPassword) && !$authenticated ) {
136
			return new JSONResponse(
137
				['message' => 'No permission to access the share'],
138
				Http::STATUS_BAD_REQUEST
139
			);
140
		}
141
142
		$share->setSharedWith($shareWith);
143
144
		try {
145
			$this->federatedShareProvider->create($share);
146
		} catch (\Exception $e) {
147
			return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
148
		}
149
150
		return new JSONResponse(['remoteUrl' => $server]);
151
	}
152
153
	/**
154
	 * ask other server to get a federated share
155
	 *
156
	 * @NoAdminRequired
157
	 *
158
	 * @param string $token
159
	 * @param string $remote
160
	 * @param string $password
161
	 * @param string $owner (only for legacy reasons, can be removed with legacyMountPublicLink())
162
	 * @param string $ownerDisplayName (only for legacy reasons, can be removed with legacyMountPublicLink())
163
	 * @param string $name (only for legacy reasons, can be removed with legacyMountPublicLink())
164
	 * @return JSONResponse
165
	 */
166
	public function askForFederatedShare($token, $remote, $password = '', $owner = '', $ownerDisplayName = '', $name = '') {
167
		// check if server admin allows to mount public links from other servers
168
		if ($this->federatedShareProvider->isIncomingServer2serverShareEnabled() === false) {
169
			return new JSONResponse(['message' => $this->l->t('Server to server sharing is not enabled on this server')], Http::STATUS_BAD_REQUEST);
170
		}
171
172
		$shareWith = $this->userSession->getUser()->getUID() . '@' . $this->addressHandler->generateRemoteURL();
173
174
		$httpClient = $this->clientService->newClient();
175
176
		try {
177
			$response = $httpClient->post($remote . '/index.php/apps/federatedfilesharing/createFederatedShare',
178
				[
179
					'body' =>
180
						[
181
							'token' => $token,
182
							'shareWith' => rtrim($shareWith, '/'),
183
							'password' => $password
184
						],
185
					'connect_timeout' => 10,
186
				]
187
			);
188
		} catch (\Exception $e) {
189
			if (empty($password)) {
190
				$message = $this->l->t("Couldn't establish a federated share.");
191
			} else {
192
				$message = $this->l->t("Couldn't establish a federated share, maybe the password was wrong.");
193
			}
194
			return new JSONResponse(['message' => $message], Http::STATUS_BAD_REQUEST);
195
		}
196
197
		$body = $response->getBody();
198
		$result = json_decode($body, true);
199
200
		if (is_array($result) && isset($result['remoteUrl'])) {
201
			return new JSONResponse(['message' => $this->l->t('Federated Share request was successful, you will receive a invitation. Check your notifications.')]);
202
		}
203
204
		// if we doesn't get the expected response we assume that we try to add
205
		// a federated share from a Nextcloud <= 9 server
206
		return $this->legacyMountPublicLink($token, $remote, $password, $name, $owner, $ownerDisplayName);
207
	}
208
209
	/**
210
	 * Allow Nextcloud to mount a public link directly
211
	 *
212
	 * This code was copied from the apps/files_sharing/ajax/external.php with
213
	 * minimal changes, just to guarantee backward compatibility
214
	 *
215
	 * ToDo: Remove this method once Nextcloud 9 reaches end of life
216
	 *
217
	 * @param string $token
218
	 * @param string $remote
219
	 * @param string $password
220
	 * @param string $name
221
	 * @param string $owner
222
	 * @param string $ownerDisplayName
223
	 * @return JSONResponse
224
	 */
225
	private function legacyMountPublicLink($token, $remote, $password, $name, $owner, $ownerDisplayName) {
226
227
		// Check for invalid name
228
		if (!\OCP\Util::isValidFileName($name)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Util::isValidFileName() has been deprecated with message: 8.1.0 use \OC\Files\View::verifyPath()

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
			return new JSONResponse(['message' => $this->l->t('The mountpoint name contains invalid characters.')], Http::STATUS_BAD_REQUEST);
230
		}
231
		$currentUser = $this->userSession->getUser()->getUID();
232
		$currentServer = $this->addressHandler->generateRemoteURL();
233
		if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer)) {
234
			return new JSONResponse(['message' => $this->l->t('Not allowed to create a federated share with the owner.')], Http::STATUS_BAD_REQUEST);
235
		}
236
		$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager(
237
			\OC::$server->getMemCacheFactory(),
238
			\OC::$server->getHTTPClientService()
239
		);
240
		$externalManager = new \OCA\Files_Sharing\External\Manager(
241
			\OC::$server->getDatabaseConnection(),
242
			\OC\Files\Filesystem::getMountManager(),
243
			\OC\Files\Filesystem::getLoader(),
244
			\OC::$server->getHTTPHelper(),
0 ignored issues
show
Deprecated Code introduced by
The method OC\Server::getHTTPHelper() has been deprecated with message: Use getHTTPClientService()

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

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

Loading history...
245
			\OC::$server->getNotificationManager(),
246
			$discoveryManager,
247
			\OC::$server->getUserSession()->getUser()->getUID()
248
		);
249
250
		// check for ssl cert
251
		if (substr($remote, 0, 5) === 'https') {
252
			try {
253
				$client = $this->clientService->newClient();
254
				$client->get($remote, [
255
					'timeout' => 10,
256
					'connect_timeout' => 10,
257
				])->getBody();
258
			} catch (\Exception $e) {
259
				return new JSONResponse(['message' => $this->l->t('Invalid or untrusted SSL certificate')], Http::STATUS_BAD_REQUEST);
260
			}
261
		}
262
		$mount = $externalManager->addShare($remote, $token, $password, $name, $ownerDisplayName, true);
263
		/**
264
		 * @var \OCA\Files_Sharing\External\Storage $storage
265
		 */
266
		$storage = $mount->getStorage();
267
		try {
268
			// check if storage exists
269
			$storage->checkStorageAvailability();
270
		} catch (\OCP\Files\StorageInvalidException $e) {
271
			// note: checkStorageAvailability will already remove the invalid share
272
			\OCP\Util::writeLog(
273
				'federatedfilesharing',
274
				'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
275
				\OCP\Util::DEBUG
276
			);
277
			return new JSONResponse(['message' => $this->l->t('Could not authenticate to remote share, password might be wrong')], Http::STATUS_BAD_REQUEST);
278
		} catch (\Exception $e) {
279
			\OCP\Util::writeLog(
280
				'federatedfilesharing',
281
				'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
282
				\OCP\Util::DEBUG
283
			);
284
			$externalManager->removeShare($mount->getMountPoint());
285
			return new JSONResponse(['message' => $this->l->t('Storage not valid')], Http::STATUS_BAD_REQUEST);
286
		}
287
		$result = $storage->file_exists('');
288
		if ($result) {
289
			try {
290
				$storage->getScanner()->scanAll();
291
				return new JSONResponse(
292
					[
293
						'message' => $this->l->t('Federated Share successfully added'),
294
						'legacyMount' => '1'
295
					]
296
				);
297
			} catch (\OCP\Files\StorageInvalidException $e) {
298
				\OCP\Util::writeLog(
299
					'federatedfilesharing',
300
					'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
301
					\OCP\Util::DEBUG
302
				);
303
				return new JSONResponse(['message' => $this->l->t('Storage not valid')], Http::STATUS_BAD_REQUEST);
304
			} catch (\Exception $e) {
305
				\OCP\Util::writeLog(
306
					'federatedfilesharing',
307
					'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
308
					\OCP\Util::DEBUG
309
				);
310
				return new JSONResponse(['message' => $this->l->t('Couldn\'t add remote share')], Http::STATUS_BAD_REQUEST);
311
			}
312
		} else {
313
			$externalManager->removeShare($mount->getMountPoint());
314
			\OCP\Util::writeLog(
315
				'federatedfilesharing',
316
				'Couldn\'t add remote share',
317
				\OCP\Util::DEBUG
318
			);
319
			return new JSONResponse(['message' => $this->l->t('Couldn\'t add remote share')], Http::STATUS_BAD_REQUEST);
320
		}
321
322
	}
323
324
}
325