Passed
Push — master ( b8b4d2...dd9780 )
by Joas
16:34 queued 26s
created

RequestHandlerController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 13
dl 0
loc 27
rs 9.8666
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 Bjoern Schiessle <[email protected]>
6
 * @author Björn Schießle <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Joas Schilling <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 *
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
namespace OCA\FederatedFileSharing\Controller;
29
30
use OCA\FederatedFileSharing\AddressHandler;
31
use OCA\FederatedFileSharing\FederatedShareProvider;
32
use OCA\FederatedFileSharing\Notifications;
33
use OCP\AppFramework\Http;
34
use OCP\AppFramework\OCS\OCSBadRequestException;
35
use OCP\AppFramework\OCS\OCSException;
36
use OCP\AppFramework\OCS\OCSForbiddenException;
37
use OCP\AppFramework\OCSController;
38
use OCP\Constants;
39
use OCP\EventDispatcher\IEventDispatcher;
40
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
41
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
42
use OCP\Federation\ICloudFederationFactory;
43
use OCP\Federation\ICloudFederationProviderManager;
44
use OCP\Federation\ICloudIdManager;
45
use OCP\IDBConnection;
46
use OCP\IRequest;
47
use OCP\IUserManager;
48
use OCP\Log\Audit\CriticalActionPerformedEvent;
49
use OCP\Share;
50
use OCP\Share\Exceptions\ShareNotFound;
51
use Psr\Log\LoggerInterface;
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
introduced by
The private property $shareTable is not used, and could be removed.
Loading history...
75
76
	/** @var ICloudIdManager */
77
	private $cloudIdManager;
78
79
	/** @var LoggerInterface */
80
	private $logger;
81
82
	/** @var ICloudFederationFactory */
83
	private $cloudFederationFactory;
84
85
	/** @var ICloudFederationProviderManager */
86
	private $cloudFederationProviderManager;
87
88
	/** @var IEventDispatcher */
89
	private $eventDispatcher;
90
91
	public function __construct(string $appName,
92
								IRequest $request,
93
								FederatedShareProvider $federatedShareProvider,
94
								IDBConnection $connection,
95
								Share\IManager $shareManager,
96
								Notifications $notifications,
97
								AddressHandler $addressHandler,
98
								IUserManager $userManager,
99
								ICloudIdManager $cloudIdManager,
100
								LoggerInterface $logger,
101
								ICloudFederationFactory $cloudFederationFactory,
102
								ICloudFederationProviderManager $cloudFederationProviderManager,
103
								IEventDispatcher $eventDispatcher
104
	) {
105
		parent::__construct($appName, $request);
106
107
		$this->federatedShareProvider = $federatedShareProvider;
108
		$this->connection = $connection;
109
		$this->shareManager = $shareManager;
110
		$this->notifications = $notifications;
111
		$this->addressHandler = $addressHandler;
112
		$this->userManager = $userManager;
113
		$this->cloudIdManager = $cloudIdManager;
114
		$this->logger = $logger;
115
		$this->cloudFederationFactory = $cloudFederationFactory;
116
		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
117
		$this->eventDispatcher = $eventDispatcher;
118
	}
119
120
	/**
121
	 * @NoCSRFRequired
122
	 * @PublicPage
123
	 *
124
	 * create a new share
125
	 *
126
	 * @return Http\DataResponse
127
	 * @throws OCSException
128
	 */
129
	public function createShare() {
130
		$remote = isset($_POST['remote']) ? $_POST['remote'] : null;
131
		$token = isset($_POST['token']) ? $_POST['token'] : null;
132
		$name = isset($_POST['name']) ? $_POST['name'] : null;
133
		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
134
		$sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
135
		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
136
		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
137
		$sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
138
		$ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
139
140
		if ($ownerFederatedId === null) {
141
			$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
142
		}
143
		// if the owner of the share and the initiator are the same user
144
		// we also complete the federated share ID for the initiator
145
		if ($sharedByFederatedId === null && $owner === $sharedBy) {
146
			$sharedByFederatedId = $ownerFederatedId;
147
		}
148
149
		$share = $this->cloudFederationFactory->getCloudFederationShare(
150
			$shareWith,
151
			$name,
152
			'',
153
			$remoteId,
154
			$ownerFederatedId,
155
			$owner,
156
			$sharedByFederatedId,
157
			$sharedBy,
158
			$token,
159
			'user',
160
			'file'
161
		);
162
163
		try {
164
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
165
			$provider->shareReceived($share);
166
			if ($sharedByFederatedId === $ownerFederatedId) {
167
					$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was created by "%s" and shared with "%s"', [$name, $ownerFederatedId, $shareWith]));
168
			} else {
169
					$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was shared by "%s" (resource owner is: "%s") and shared with "%s"', [$name, $sharedByFederatedId, $ownerFederatedId, $shareWith]));
170
			}
171
		} catch (ProviderDoesNotExistsException $e) {
172
			throw new OCSException('Server does not support federated cloud sharing', 503);
173
		} catch (ProviderCouldNotAddShareException $e) {
174
			throw new OCSException($e->getMessage(), 400);
175
		} catch (\Exception $e) {
176
			throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
177
		}
178
179
		return new Http\DataResponse();
180
	}
181
182
	/**
183
	 * @NoCSRFRequired
184
	 * @PublicPage
185
	 *
186
	 * create re-share on behalf of another user
187
	 *
188
	 * @param int $id
189
	 * @return Http\DataResponse
190
	 * @throws OCSBadRequestException
191
	 * @throws OCSException
192
	 * @throws OCSForbiddenException
193
	 */
194
	public function reShare($id) {
195
		$token = $this->request->getParam('token', null);
196
		$shareWith = $this->request->getParam('shareWith', null);
197
		$permission = (int)$this->request->getParam('permission', null);
198
		$remoteId = (int)$this->request->getParam('remoteId', null);
199
200
		if ($id === null ||
201
			$token === null ||
202
			$shareWith === null ||
203
			$permission === null ||
204
			$remoteId === null
205
		) {
206
			throw new OCSBadRequestException();
207
		}
208
209
		$notification = [
210
			'sharedSecret' => $token,
211
			'shareWith' => $shareWith,
212
			'senderId' => $remoteId,
213
			'message' => 'Recipient of a share ask the owner to reshare the file'
214
		];
215
216
		try {
217
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
218
			[$newToken, $localId] = $provider->notificationReceived('REQUEST_RESHARE', $id, $notification);
219
			return new Http\DataResponse([
220
				'token' => $newToken,
221
				'remoteId' => $localId
222
			]);
223
		} catch (ProviderDoesNotExistsException $e) {
224
			throw new OCSException('Server does not support federated cloud sharing', 503);
225
		} catch (ShareNotFound $e) {
226
			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
227
		} catch (\Exception $e) {
228
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
229
		}
230
231
		throw new OCSBadRequestException();
232
	}
233
234
235
	/**
236
	 * @NoCSRFRequired
237
	 * @PublicPage
238
	 *
239
	 * accept server-to-server share
240
	 *
241
	 * @param int $id
242
	 * @return Http\DataResponse
243
	 * @throws OCSException
244
	 * @throws ShareNotFound
245
	 * @throws \OCP\HintException
246
	 */
247
	public function acceptShare($id) {
248
		$token = isset($_POST['token']) ? $_POST['token'] : null;
249
250
		$notification = [
251
			'sharedSecret' => $token,
252
			'message' => 'Recipient accept the share'
253
		];
254
255
		try {
256
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
257
			$provider->notificationReceived('SHARE_ACCEPTED', $id, $notification);
258
			$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was accepted', [$id]));
259
		} catch (ProviderDoesNotExistsException $e) {
260
			throw new OCSException('Server does not support federated cloud sharing', 503);
261
		} catch (ShareNotFound $e) {
262
			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
263
		} catch (\Exception $e) {
264
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
265
		}
266
267
		return new Http\DataResponse();
268
	}
269
270
	/**
271
	 * @NoCSRFRequired
272
	 * @PublicPage
273
	 *
274
	 * decline server-to-server share
275
	 *
276
	 * @param int $id
277
	 * @return Http\DataResponse
278
	 * @throws OCSException
279
	 */
280
	public function declineShare($id) {
281
		$token = isset($_POST['token']) ? $_POST['token'] : null;
282
283
		$notification = [
284
			'sharedSecret' => $token,
285
			'message' => 'Recipient declined the share'
286
		];
287
288
		try {
289
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
290
			$provider->notificationReceived('SHARE_DECLINED', $id, $notification);
291
			$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was declined', [$id]));
292
		} catch (ProviderDoesNotExistsException $e) {
293
			throw new OCSException('Server does not support federated cloud sharing', 503);
294
		} catch (ShareNotFound $e) {
295
			$this->logger->debug('Share not found: ' . $e->getMessage(), ['exception' => $e]);
296
		} catch (\Exception $e) {
297
			$this->logger->debug('internal server error, can not process notification: ' . $e->getMessage(), ['exception' => $e]);
298
		}
299
300
		return new Http\DataResponse();
301
	}
302
303
	/**
304
	 * @NoCSRFRequired
305
	 * @PublicPage
306
	 *
307
	 * remove server-to-server share if it was unshared by the owner
308
	 *
309
	 * @param int $id
310
	 * @return Http\DataResponse
311
	 * @throws OCSException
312
	 */
313
	public function unshare($id) {
314
		if (!$this->isS2SEnabled()) {
315
			throw new OCSException('Server does not support federated cloud sharing', 503);
316
		}
317
318
		$token = isset($_POST['token']) ? $_POST['token'] : null;
319
320
		try {
321
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
322
			$notification = ['sharedSecret' => $token];
323
			$provider->notificationReceived('SHARE_UNSHARED', $id, $notification);
324
			$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was unshared', [$id]));
325
		} catch (\Exception $e) {
326
			$this->logger->debug('processing unshare notification failed: ' . $e->getMessage(), ['exception' => $e]);
327
		}
328
329
		return new Http\DataResponse();
330
	}
331
332
	private function cleanupRemote($remote) {
333
		$remote = substr($remote, strpos($remote, '://') + 3);
334
335
		return rtrim($remote, '/');
336
	}
337
338
339
	/**
340
	 * @NoCSRFRequired
341
	 * @PublicPage
342
	 *
343
	 * federated share was revoked, either by the owner or the re-sharer
344
	 *
345
	 * @param int $id
346
	 * @return Http\DataResponse
347
	 * @throws OCSBadRequestException
348
	 */
349
	public function revoke($id) {
350
		$token = $this->request->getParam('token');
351
352
		try {
353
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
354
			$notification = ['sharedSecret' => $token];
355
			$provider->notificationReceived('RESHARE_UNDO', $id, $notification);
356
			return new Http\DataResponse();
357
		} catch (\Exception $e) {
358
			throw new OCSBadRequestException();
359
		}
360
	}
361
362
	/**
363
	 * check if server-to-server sharing is enabled
364
	 *
365
	 * @param bool $incoming
366
	 * @return bool
367
	 */
368
	private function isS2SEnabled($incoming = false) {
369
		$result = \OCP\App::isEnabled('files_sharing');
370
371
		if ($incoming) {
372
			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
373
		} else {
374
			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
375
		}
376
377
		return $result;
378
	}
379
380
	/**
381
	 * @NoCSRFRequired
382
	 * @PublicPage
383
	 *
384
	 * update share information to keep federated re-shares in sync
385
	 *
386
	 * @param int $id
387
	 * @return Http\DataResponse
388
	 * @throws OCSBadRequestException
389
	 */
390
	public function updatePermissions($id) {
391
		$token = $this->request->getParam('token', null);
392
		$ncPermissions = $this->request->getParam('permissions', null);
393
394
		try {
395
			$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
396
			$ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions);
397
			$notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions];
398
			$provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification);
399
			$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" has updated permissions "%s"', [$id, implode(', ', $ocmPermissions)]));
400
		} catch (\Exception $e) {
401
			$this->logger->debug($e->getMessage(), ['exception' => $e]);
402
			throw new OCSBadRequestException();
403
		}
404
405
		return new Http\DataResponse();
406
	}
407
408
	/**
409
	 * translate Nextcloud permissions to OCM Permissions
410
	 *
411
	 * @param $ncPermissions
412
	 * @return array
413
	 */
414
	protected function ncPermissions2ocmPermissions($ncPermissions) {
415
		$ocmPermissions = [];
416
417
		if ($ncPermissions & Constants::PERMISSION_SHARE) {
418
			$ocmPermissions[] = 'share';
419
		}
420
421
		if ($ncPermissions & Constants::PERMISSION_READ) {
422
			$ocmPermissions[] = 'read';
423
		}
424
425
		if (($ncPermissions & Constants::PERMISSION_CREATE) ||
426
			($ncPermissions & Constants::PERMISSION_UPDATE)) {
427
			$ocmPermissions[] = 'write';
428
		}
429
430
		return $ocmPermissions;
431
	}
432
433
	/**
434
	 * @NoCSRFRequired
435
	 * @PublicPage
436
	 *
437
	 * change the owner of a server-to-server share
438
	 *
439
	 * @param int $id
440
	 * @return Http\DataResponse
441
	 * @throws \InvalidArgumentException
442
	 * @throws OCSException
443
	 */
444
	public function move($id) {
445
		if (!$this->isS2SEnabled()) {
446
			throw new OCSException('Server does not support federated cloud sharing', 503);
447
		}
448
449
		$token = $this->request->getParam('token');
450
		$remote = $this->request->getParam('remote');
451
		$newRemoteId = $this->request->getParam('remote_id', $id);
452
		$cloudId = $this->cloudIdManager->resolveCloudId($remote);
453
454
		$qb = $this->connection->getQueryBuilder();
455
		$query = $qb->update('share_external')
456
			->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
457
			->set('owner', $qb->createNamedParameter($cloudId->getUser()))
458
			->set('remote_id', $qb->createNamedParameter($newRemoteId))
459
			->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
460
			->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
461
		$affected = $query->executeStatement();
462
463
		if ($affected > 0) {
464
			return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
465
		} else {
466
			throw new OCSBadRequestException('Share not found or token invalid');
467
		}
468
	}
469
}
470