Completed
Push — master ( 8b683f...7025f1 )
by Morris
29:10 queued 12:40
created

RequestHandlerController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 26
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 12
dl 26
loc 26
rs 9.504
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Joas Schilling <[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
 *
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
30
namespace OCA\FederatedFileSharing\Controller;
31
32
use OCA\FederatedFileSharing\AddressHandler;
33
use OCA\FederatedFileSharing\FederatedShareProvider;
34
use OCA\FederatedFileSharing\Notifications;
35
use OCP\AppFramework\Http;
36
use OCP\AppFramework\OCS\OCSBadRequestException;
37
use OCP\AppFramework\OCS\OCSException;
38
use OCP\AppFramework\OCS\OCSForbiddenException;
39
use OCP\AppFramework\OCSController;
40
use OCP\Constants;
41
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
42
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
43
use OCP\Federation\ICloudFederationFactory;
44
use OCP\Federation\ICloudFederationProviderManager;
45
use OCP\Federation\ICloudIdManager;
46
use OCP\IDBConnection;
47
use OCP\ILogger;
48
use OCP\IRequest;
49
use OCP\IUserManager;
50
use OCP\Share;
51
use OCP\Share\Exceptions\ShareNotFound;
52
53
class RequestHandlerController extends OCSController {
54
55
	/** @var FederatedShareProvider */
56
	private $federatedShareProvider;
57
58
	/** @var IDBConnection */
59
	private $connection;
60
61
	/** @var Share\IManager */
62
	private $shareManager;
63
64
	/** @var Notifications */
65
	private $notifications;
66
67
	/** @var AddressHandler */
68
	private $addressHandler;
69
70
	/** @var  IUserManager */
71
	private $userManager;
72
73
	/** @var string */
74
	private $shareTable = 'share';
0 ignored issues
show
Unused Code introduced by
The property $shareTable is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
75
76
	/** @var ICloudIdManager */
77
	private $cloudIdManager;
78
79
	/** @var ILogger */
80
	private $logger;
81
82
	/** @var ICloudFederationFactory */
83
	private $cloudFederationFactory;
84
85
	/** @var ICloudFederationProviderManager */
86
	private $cloudFederationProviderManager;
87
88
	/**
89
	 * Server2Server constructor.
90
	 *
91
	 * @param string $appName
92
	 * @param IRequest $request
93
	 * @param FederatedShareProvider $federatedShareProvider
94
	 * @param IDBConnection $connection
95
	 * @param Share\IManager $shareManager
96
	 * @param Notifications $notifications
97
	 * @param AddressHandler $addressHandler
98
	 * @param IUserManager $userManager
99
	 * @param ICloudIdManager $cloudIdManager
100
	 * @param ILogger $logger
101
	 * @param ICloudFederationFactory $cloudFederationFactory
102
	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
103
	 */
104 View Code Duplication
	public function __construct($appName,
105
								IRequest $request,
106
								FederatedShareProvider $federatedShareProvider,
107
								IDBConnection $connection,
108
								Share\IManager $shareManager,
109
								Notifications $notifications,
110
								AddressHandler $addressHandler,
111
								IUserManager $userManager,
112
								ICloudIdManager $cloudIdManager,
113
								ILogger $logger,
114
								ICloudFederationFactory $cloudFederationFactory,
115
								ICloudFederationProviderManager $cloudFederationProviderManager
116
	) {
117
		parent::__construct($appName, $request);
118
119
		$this->federatedShareProvider = $federatedShareProvider;
120
		$this->connection = $connection;
121
		$this->shareManager = $shareManager;
122
		$this->notifications = $notifications;
123
		$this->addressHandler = $addressHandler;
124
		$this->userManager = $userManager;
125
		$this->cloudIdManager = $cloudIdManager;
126
		$this->logger = $logger;
127
		$this->cloudFederationFactory = $cloudFederationFactory;
128
		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
129
	}
130
131
	/**
132
	 * @NoCSRFRequired
133
	 * @PublicPage
134
	 *
135
	 * create a new share
136
	 *
137
	 * @return Http\DataResponse
138
	 * @throws OCSException
139
	 */
140
	public function createShare() {
0 ignored issues
show
Coding Style introduced by
createShare uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
141
142
		$remote = isset($_POST['remote']) ? $_POST['remote'] : null;
143
		$token = isset($_POST['token']) ? $_POST['token'] : null;
144
		$name = isset($_POST['name']) ? $_POST['name'] : null;
145
		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
146
		$sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
147
		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
148
		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
149
		$sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
150
		$ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
151
152
		if ($ownerFederatedId === null) {
153
			$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
154
		}
155
		// if the owner of the share and the initiator are the same user
156
		// we also complete the federated share ID for the initiator
157
		if ($sharedByFederatedId === null && $owner === $sharedBy) {
158
			$sharedByFederatedId = $ownerFederatedId;
159
		}
160
161
		$share = $this->cloudFederationFactory->getCloudFederationShare(
162
			$shareWith,
163
			$name,
164
			'',
165
			$remoteId,
166
			$ownerFederatedId,
167
			$owner,
168
			$sharedByFederatedId,
169
			$sharedBy,
170
			$token,
171
			'user',
172
			'file'
173
		);
174
175
		try {
176
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
177
			$provider->shareReceived($share);
178
		} catch (ProviderDoesNotExistsException $e) {
179
			throw new OCSException('Server does not support federated cloud sharing', 503);
180
		} catch (ProviderCouldNotAddShareException $e) {
181
			throw new OCSException($e->getMessage(), 400);
182
		} catch (\Exception $e) {
183
			throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
184
		}
185
186
		return new Http\DataResponse();
187
	}
188
189
	/**
190
	 * @NoCSRFRequired
191
	 * @PublicPage
192
	 *
193
	 * create re-share on behalf of another user
194
	 *
195
	 * @param int $id
196
	 * @return Http\DataResponse
197
	 * @throws OCSBadRequestException
198
	 * @throws OCSException
199
	 * @throws OCSForbiddenException
200
	 */
201
	public function reShare($id) {
202
203
		$token = $this->request->getParam('token', null);
204
		$shareWith = $this->request->getParam('shareWith', null);
205
		$permission = (int)$this->request->getParam('permission', null);
206
		$remoteId = (int)$this->request->getParam('remoteId', null);
207
208
		if ($id === null ||
209
			$token === null ||
210
			$shareWith === null ||
211
			$permission === null ||
212
			$remoteId === null
213
		) {
214
			throw new OCSBadRequestException();
215
		}
216
217
		$notification = [
218
			'sharedSecret' => $token,
219
			'shareWith' => $shareWith,
220
			'senderId' => $remoteId,
221
			'message' => 'Recipient of a share ask the owner to reshare the file'
222
		];
223
224
		try {
225
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
226
			list($newToken, $localId) = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification);
227
			return new Http\DataResponse([
228
				'token' => $newToken,
229
				'remoteId' => $localId
230
			]);
231
		} catch (ProviderDoesNotExistsException $e) {
232
			throw new OCSException('Server does not support federated cloud sharing', 503);
233
		} catch (ShareNotFound $e) {
234
			$this->logger->debug('Share not found: ' . $e->getMessage());
235
		} catch (\Exception $e) {
236
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage());
237
		}
238
239
		throw new OCSBadRequestException();
240
	}
241
242
243
	/**
244
	 * @NoCSRFRequired
245
	 * @PublicPage
246
	 *
247
	 * accept server-to-server share
248
	 *
249
	 * @param int $id
250
	 * @return Http\DataResponse
251
	 * @throws OCSException
252
	 * @throws ShareNotFound
253
	 * @throws \OC\HintException
254
	 */
255 View Code Duplication
	public function acceptShare($id) {
0 ignored issues
show
Coding Style introduced by
acceptShare uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
256
257
		$token = isset($_POST['token']) ? $_POST['token'] : null;
258
259
		$notification = [
260
			'sharedSecret' => $token,
261
			'message' => 'Recipient accept the share'
262
		];
263
264
		try {
265
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
266
			$provider->notificationReceived('SHARE_ACCEPTED', $id, $notification);
267
		} catch (ProviderDoesNotExistsException $e) {
268
			throw new OCSException('Server does not support federated cloud sharing', 503);
269
		} catch (ShareNotFound $e) {
270
			$this->logger->debug('Share not found: ' . $e->getMessage());
271
		} catch (\Exception $e) {
272
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage());
273
		}
274
275
		return new Http\DataResponse();
276
	}
277
278
	/**
279
	 * @NoCSRFRequired
280
	 * @PublicPage
281
	 *
282
	 * decline server-to-server share
283
	 *
284
	 * @param int $id
285
	 * @return Http\DataResponse
286
	 * @throws OCSException
287
	 */
288 View Code Duplication
	public function declineShare($id) {
0 ignored issues
show
Coding Style introduced by
declineShare uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
289
290
		$token = isset($_POST['token']) ? $_POST['token'] : null;
291
292
		$notification = [
293
			'sharedSecret' => $token,
294
			'message' => 'Recipient declined the share'
295
		];
296
297
		try {
298
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
299
			$provider->notificationReceived('SHARE_DECLINED', $id, $notification);
300
		} catch (ProviderDoesNotExistsException $e) {
301
			throw new OCSException('Server does not support federated cloud sharing', 503);
302
		} catch (ShareNotFound $e) {
303
			$this->logger->debug('Share not found: ' . $e->getMessage());
304
		} catch (\Exception $e) {
305
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage());
306
		}
307
308
		return new Http\DataResponse();
309
	}
310
311
	/**
312
	 * @NoCSRFRequired
313
	 * @PublicPage
314
	 *
315
	 * remove server-to-server share if it was unshared by the owner
316
	 *
317
	 * @param int $id
318
	 * @return Http\DataResponse
319
	 * @throws OCSException
320
	 */
321
	public function unshare($id) {
0 ignored issues
show
Coding Style introduced by
unshare uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
322
323
		if (!$this->isS2SEnabled()) {
324
			throw new OCSException('Server does not support federated cloud sharing', 503);
325
		}
326
327
		$token = isset($_POST['token']) ? $_POST['token'] : null;
328
329
		try {
330
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
331
			$notification = ['sharedSecret' => $token];
332
			$provider->notificationReceived('SHARE_UNSHARED', $id, $notification);
333
		} catch (\Exception $e) {
334
			$this->logger->debug('processing unshare notification failed: ' . $e->getMessage());
335
		}
336
337
		return new Http\DataResponse();
338
	}
339
340
	private function cleanupRemote($remote) {
341
		$remote = substr($remote, strpos($remote, '://') + 3);
342
343
		return rtrim($remote, '/');
344
	}
345
346
347
	/**
348
	 * @NoCSRFRequired
349
	 * @PublicPage
350
	 *
351
	 * federated share was revoked, either by the owner or the re-sharer
352
	 *
353
	 * @param int $id
354
	 * @return Http\DataResponse
355
	 * @throws OCSBadRequestException
356
	 */
357
	public function revoke($id) {
358
359
		$token = $this->request->getParam('token');
360
361
		try {
362
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
363
			$notification = ['sharedSecret' => $token];
364
			$provider->notificationReceived('RESHARE_UNDO', $id, $notification);
365
			return new Http\DataResponse();
366
		} catch (\Exception $e) {
367
			throw new OCSBadRequestException();
368
		}
369
370
	}
371
372
	/**
373
	 * check if server-to-server sharing is enabled
374
	 *
375
	 * @param bool $incoming
376
	 * @return bool
377
	 */
378 View Code Duplication
	private function isS2SEnabled($incoming = false) {
379
380
		$result = \OCP\App::isEnabled('files_sharing');
381
382
		if ($incoming) {
383
			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
384
		} else {
385
			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
386
		}
387
388
		return $result;
389
	}
390
391
	/**
392
	 * @NoCSRFRequired
393
	 * @PublicPage
394
	 *
395
	 * update share information to keep federated re-shares in sync
396
	 *
397
	 * @param int $id
398
	 * @return Http\DataResponse
399
	 * @throws OCSBadRequestException
400
	 */
401
	public function updatePermissions($id) {
402
		$token = $this->request->getParam('token', null);
403
		$ncPermissions = $this->request->getParam('permissions', null);
404
405
		try {
406
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
407
			$ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions);
408
			$notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions];
409
			$provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification);
410
		} catch (\Exception $e) {
411
			$this->logger->debug($e->getMessage());
412
			throw new OCSBadRequestException();
413
		}
414
415
		return new Http\DataResponse();
416
	}
417
418
	/**
419
	 * translate Nextcloud permissions to OCM Permissions
420
	 *
421
	 * @param $ncPermissions
422
	 * @return array
423
	 */
424 View Code Duplication
	protected function ncPermissions2ocmPermissions($ncPermissions) {
425
426
		$ocmPermissions = [];
427
428
		if ($ncPermissions & Constants::PERMISSION_SHARE) {
429
			$ocmPermissions[] = 'share';
430
		}
431
432
		if ($ncPermissions & Constants::PERMISSION_READ) {
433
			$ocmPermissions[] = 'read';
434
		}
435
436
		if (($ncPermissions & Constants::PERMISSION_CREATE) ||
437
			($ncPermissions & Constants::PERMISSION_UPDATE)) {
438
			$ocmPermissions[] = 'write';
439
		}
440
441
		return $ocmPermissions;
442
443
	}
444
445
	/**
446
	 * @NoCSRFRequired
447
	 * @PublicPage
448
	 *
449
	 * change the owner of a server-to-server share
450
	 *
451
	 * @param int $id
452
	 * @return Http\DataResponse
453
	 * @throws \InvalidArgumentException
454
	 * @throws OCSException
455
	 */
456
	public function move($id) {
457
458
		if (!$this->isS2SEnabled()) {
459
			throw new OCSException('Server does not support federated cloud sharing', 503);
460
		}
461
462
		$token = $this->request->getParam('token');
463
		$remote = $this->request->getParam('remote');
464
		$newRemoteId = $this->request->getParam('remote_id', $id);
465
		$cloudId = $this->cloudIdManager->resolveCloudId($remote);
466
467
		$qb = $this->connection->getQueryBuilder();
468
		$query = $qb->update('share_external')
469
			->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
470
			->set('owner', $qb->createNamedParameter($cloudId->getUser()))
471
			->set('remote_id', $qb->createNamedParameter($newRemoteId))
472
			->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
473
			->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
474
		$affected = $query->execute();
475
476
		if ($affected > 0) {
477
			return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
478
		} else {
479
			throw new OCSBadRequestException('Share not found or token invalid');
480
		}
481
	}
482
}
483