Completed
Pull Request — master (#32303)
by Victor
10:42
created

RequestHandlerController::revoke()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 3
nop 1
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Björn Schießle <[email protected]>
5
 * @author Joas Schilling <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * @copyright Copyright (c) 2018, ownCloud GmbH
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OCA\FederatedFileSharing\Controller;
28
29
use OC\OCS\Result;
30
use OCA\FederatedFileSharing\Address;
31
use OCA\FederatedFileSharing\AddressHandler;
32
use OCA\FederatedFileSharing\FederatedShareProvider;
33
use OCA\FederatedFileSharing\FedShareManager;
34
use OCA\FederatedFileSharing\Ocm\Exception\BadRequestException;
35
use OCA\FederatedFileSharing\Ocm\Exception\NotImplementedException;
36
use OCA\FederatedFileSharing\Ocm\Exception\OcmException;
37
use OCP\App\IAppManager;
38
use OCP\AppFramework\Http;
39
use OCP\AppFramework\OCSController;
40
use OCP\Constants;
41
use OCP\IRequest;
42
use OCP\IUserManager;
43
use OCP\Share;
44
use OCP\Share\IShare;
45
46
/**
47
 * Class RequestHandlerController
48
 *
49
 * Handles OCS Request to the federated share API
50
 *
51
 * @package OCA\FederatedFileSharing\API
52
 */
53
class RequestHandlerController extends OCSController {
54
55
	/** @var FederatedShareProvider */
56
	private $federatedShareProvider;
57
58
	/** @var IAppManager */
59
	private $appManager;
60
61
	/** @var IUserManager */
62
	private $userManager;
63
64
	/** @var AddressHandler */
65
	private $addressHandler;
66
67
	/** @var  FedShareManager */
68
	private $fedShareManager;
69
70
	/**
71
	 * Server2Server constructor.
72
	 *
73
	 * @param string $appName
74
	 * @param IRequest $request
75
	 * @param FederatedShareProvider $federatedShareProvider
76
	 * @param IAppManager $appManager
77
	 * @param IUserManager $userManager
78
	 * @param AddressHandler $addressHandler
79
	 * @param FedShareManager $fedShareManager
80
	 */
81
	public function __construct($appName,
82
								IRequest $request,
83
								FederatedShareProvider $federatedShareProvider,
84
								IAppManager $appManager,
85
								IUserManager $userManager,
86
								AddressHandler $addressHandler,
87
								FedShareManager $fedShareManager
88
	) {
89
		parent::__construct($appName, $request);
90
91
		$this->federatedShareProvider = $federatedShareProvider;
92
		$this->appManager = $appManager;
93
		$this->userManager = $userManager;
94
		$this->addressHandler = $addressHandler;
95
		$this->fedShareManager = $fedShareManager;
96
	}
97
98
	/**
99
	 * @NoCSRFRequired
100
	 * @PublicPage
101
	 *
102
	 * create a new share
103
	 *
104
	 * @return Result
105
	 */
106
	public function createShare() {
107
		try {
108
			$this->assertIncomingSharingEnabled();
109
			$remote = $this->request->getParam('remote', null);
110
			$token = $this->request->getParam('token', null);
111
			$name = $this->request->getParam('name', null);
112
			$owner = $this->request->getParam('owner', null);
113
			$sharedBy = $this->request->getParam('sharedBy', null);
114
			$shareWith = $this->request->getParam('shareWith', null);
115
			$remoteId = $this->request->getParam('remoteId', null);
116
			$sharedByFederatedId = $this->request->getParam(
117
				'sharedByFederatedId',
118
				null
119
			);
120
			$ownerFederatedId = $this->request->getParam('ownerFederatedId', null);
121
			$hasMissingParams = $this->hasNull(
122
				[$remote, $token, $name, $owner, $remoteId, $shareWith]
123
			);
124
			if ($hasMissingParams) {
125
				throw new BadRequestException(
126
					'server can not add remote share, missing parameter'
127
				);
128
			}
129
			if (!\OCP\Util::isValidFileName($name)) {
130
				throw new BadRequestException(
131
					'The mountpoint name contains invalid characters.'
132
				);
133
			}
134
			// FIXME this should be a method in the user management instead
135
			\OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG);
136
			\OCP\Util::emitHook(
137
				'\OCA\Files_Sharing\API\Server2Server',
138
				'preLoginNameUsedAsUserName',
139
				['uid' => &$shareWith]
140
			);
141
			\OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG);
142
			if (!$this->userManager->userExists($shareWith)) {
143
				throw new BadRequestException('User does not exist');
144
			}
145
146
			if ($ownerFederatedId === null) {
147
				$ownerFederatedId = $owner . '@' . $this->addressHandler->normalizeRemote($remote);
148
			}
149
			// if the owner of the share and the initiator are the same user
150
			// we also complete the federated share ID for the initiator
151
			if ($sharedByFederatedId === null && $owner === $sharedBy) {
152
				$sharedByFederatedId = $ownerFederatedId;
153
			}
154
155
			$ownerAddress = new Address($ownerFederatedId);
156
			$sharedByAddress = new Address($sharedByFederatedId);
157
158
			$this->fedShareManager->createShare(
159
				$ownerAddress,
160
				$sharedByAddress,
161
				$shareWith,
162
				$remoteId,
163
				$name,
164
				$token
165
			);
166
		} catch (OcmException $e) {
167
			return new Result(
168
				null,
169
				$e->getHttpStatusCode(),
170
				$e->getMessage()
171
			);
172
		} catch (\Exception $e) {
173
			\OCP\Util::writeLog(
174
				'files_sharing',
175
				'server can not add remote share, ' . $e->getMessage(),
176
				\OCP\Util::ERROR
177
			);
178
			return new Result(
179
				null,
180
				Http::STATUS_INTERNAL_SERVER_ERROR,
181
				'internal server error, was not able to add share from ' . $remote
0 ignored issues
show
Bug introduced by
The variable $remote does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
182
			);
183
		}
184
		return new Result();
185
	}
186
187
	/**
188
	 * @NoCSRFRequired
189
	 * @PublicPage
190
	 *
191
	 * create re-share on behalf of another user
192
	 *
193
	 * @param int $id
194
	 *
195
	 * @return Result
196
	 */
197
	public function reShare($id) {
198
		$token = $this->request->getParam('token', null);
199
		$shareWith = $this->request->getParam('shareWith', null);
200
		$permission = $this->request->getParam('permission', null);
201
		$remoteId = $this->request->getParam('remoteId', null);
202
203
		if ($this->hasNull([$id, $token, $shareWith, $permission, $remoteId])) {
204
			return new Result(null, Http::STATUS_BAD_REQUEST);
205
		}
206
207
		try {
208
			$permission = (int) $permission;
209
			$remoteId = (int) $remoteId;
210
			$share = $this->getValidShare($id);
211
212
			// don't allow to share a file back to the owner
213
			list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
214
			$owner = $share->getShareOwner();
215
			$currentServer = $this->addressHandler->generateRemoteURL();
216
			if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
217
				return new Result(null, Http::STATUS_FORBIDDEN);
218
			}
219
220
			$reSharingAllowed = $share->getPermissions() & Constants::PERMISSION_SHARE;
221
			if (!$reSharingAllowed) {
222
				return new Result(null, Http::STATUS_BAD_REQUEST);
223
			}
224
			$result = $this->fedShareManager->reShare(
225
				$share,
226
				$remoteId,
227
				$shareWith,
228
				$permission
229
			);
230
		} catch (Share\Exceptions\ShareNotFound $e) {
231
			return new Result(null, Http::STATUS_NOT_FOUND);
232
		} catch (BadRequestException $e) {
233
			return new Result(null, Http::STATUS_FORBIDDEN);
234
		} catch (\Exception $e) {
235
			return new Result(null, Http::STATUS_BAD_REQUEST);
236
		}
237
238
		return new Result(
239
			[
240
				'token' => $result->getToken(),
241
				'remoteId' => $result->getId()
242
			]
243
		);
244
	}
245
246
	/**
247
	 * @NoCSRFRequired
248
	 * @PublicPage
249
	 *
250
	 * accept server-to-server share
251
	 *
252
	 * @param int $id
253
	 *
254
	 * @return Result
255
	 */
256 View Code Duplication
	public function acceptShare($id) {
257
		try {
258
			$this->assertOutgoingSharingEnabled();
259
			$share = $this->getValidShare($id);
260
			$this->fedShareManager->acceptShare($share);
261
		} catch (NotImplementedException $e) {
262
			return new Result(
263
				null,
264
				Http::STATUS_SERVICE_UNAVAILABLE,
265
				'Server does not support federated cloud sharing'
266
			);
267
		} catch (Share\Exceptions\ShareNotFound $e) {
268
			// pass
269
		}
270
		return new Result();
271
	}
272
273
	/**
274
	 * @NoCSRFRequired
275
	 * @PublicPage
276
	 *
277
	 * decline server-to-server share
278
	 *
279
	 * @param int $id
280
	 *
281
	 * @return Result
282
	 */
283 View Code Duplication
	public function declineShare($id) {
284
		try {
285
			$this->assertOutgoingSharingEnabled();
286
			$share = $this->getValidShare($id);
287
			$this->fedShareManager->declineShare($share);
288
		} catch (NotImplementedException $e) {
289
			return new Result(
290
				null,
291
				Http::STATUS_SERVICE_UNAVAILABLE,
292
				'Server does not support federated cloud sharing'
293
			);
294
		} catch (Share\Exceptions\ShareNotFound $e) {
295
			// pass
296
		}
297
298
		return new Result();
299
	}
300
301
	/**
302
	 * @NoCSRFRequired
303
	 * @PublicPage
304
	 *
305
	 * remove server-to-server share if it was unshared by the owner
306
	 *
307
	 * @param int $id
308
	 *
309
	 * @return Result
310
	 */
311
	public function unshare($id) {
312
		try {
313
			$this->assertOutgoingSharingEnabled();
314
			$token = $this->request->getParam('token', null);
315
			if ($token && $id) {
316
				$this->fedShareManager->unshare($id, $token);
317
			}
318
		} catch (NotImplementedException $e) {
319
			return new Result(
320
				null,
321
				Http::STATUS_SERVICE_UNAVAILABLE,
322
				'Server does not support federated cloud sharing'
323
			);
324
		} catch (\Exception $e) {
325
			// pass
326
		}
327
		return new Result();
328
	}
329
330
	/**
331
	 * @NoCSRFRequired
332
	 * @PublicPage
333
	 *
334
	 * federated share was revoked, either by the owner or the re-sharer
335
	 *
336
	 * @param int $id
337
	 *
338
	 * @return Result
339
	 */
340
	public function revoke($id) {
341
		try {
342
			$share = $this->getValidShare($id);
343
			$this->fedShareManager->revoke($share);
344
		} catch (\Exception $e) {
345
			return new Result(null, Http::STATUS_BAD_REQUEST);
346
		}
347
348
		return new Result();
349
	}
350
351
	/**
352
	 * @NoCSRFRequired
353
	 * @PublicPage
354
	 *
355
	 * update share information to keep federated re-shares in sync
356
	 *
357
	 * @param int $id
358
	 *
359
	 * @return Result
360
	 */
361
	public function updatePermissions($id) {
362
		try {
363
			$permissions = $this->request->getParam('permissions', null);
364
365
			$share = $this->getValidShare($id);
366
			$validPermission = \ctype_digit((string)$permissions);
367
			if (!$validPermission) {
368
				throw new \Exception();
369
			}
370
			$this->fedShareManager->updatePermissions($share, (int)$permissions);
371
		} catch (\Exception $e) {
372
			return new Result(null, Http::STATUS_BAD_REQUEST);
373
		}
374
375
		return new Result();
376
	}
377
378
	/**
379
	 * Get share by id, validate it's type and token
380
	 *
381
	 * @param int $id
382
	 *
383
	 * @return IShare
384
	 *
385
	 * @throws Share\Exceptions\ShareNotFound
386
	 * @throws BadRequestException
387
	 */
388
	protected function getValidShare($id) {
389
		$share = $this->federatedShareProvider->getShareById($id);
390
		$token = $this->request->getParam('token', null);
391
		if ($share->getShareType() !== FederatedShareProvider::SHARE_TYPE_REMOTE
392
			|| $share->getToken() !== $token
393
		) {
394
			throw new BadRequestException();
395
		}
396
		return $share;
397
	}
398
399
	/**
400
	 * Make sure that incoming shares are enabled
401
	 *
402
	 * @return void
403
	 *
404
	 * @throws NotImplementedException
405
	 */
406
	protected function assertIncomingSharingEnabled() {
407
		if (!$this->appManager->isEnabledForUser('files_sharing')
408
			|| !$this->federatedShareProvider->isIncomingServer2serverShareEnabled()
409
		) {
410
			throw new NotImplementedException();
411
		}
412
	}
413
	
414
	/**
415
	 * Make sure that outgoing shares are enabled
416
	 *
417
	 * @return void
418
	 *
419
	 * @throws NotImplementedException
420
	 */
421
	protected function assertOutgoingSharingEnabled() {
422
		if (!$this->appManager->isEnabledForUser('files_sharing')
423
			|| !$this->federatedShareProvider->isOutgoingServer2serverShareEnabled()
424
		) {
425
			throw new NotImplementedException();
426
		}
427
	}
428
429
	/**
430
	 * Check if value is null or an array has any null item
431
	 *
432
	 * @param mixed $param
433
	 *
434
	 * @return bool
435
	 */
436 View Code Duplication
	protected function hasNull($param) {
437
		if (\is_array($param)) {
438
			return \in_array(null, $param, true);
439
		} else {
440
			return $param === null;
441
		}
442
	}
443
}
444