Passed
Push — master ( b249c1...ba03c1 )
by Roeland
11:56
created

AuthSettingsController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 8
dl 0
loc 15
rs 10
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 Christoph Wurst <[email protected]>
6
 * @author Fabrizio Steiner <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Marcel Waldvogel <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\Settings\Controller;
29
30
use BadMethodCallException;
31
use OC\AppFramework\Http;
32
use OC\Authentication\Exceptions\InvalidTokenException;
33
use OC\Authentication\Exceptions\PasswordlessTokenException;
34
use OC\Authentication\Token\IProvider;
35
use OC\Authentication\Token\IToken;
36
use OC\Settings\Activity\Provider;
37
use OCP\Activity\IManager;
38
use OCP\AppFramework\Controller;
39
use OCP\AppFramework\Http\JSONResponse;
40
use OCP\ILogger;
41
use OCP\IRequest;
42
use OCP\ISession;
43
use OCP\Security\ISecureRandom;
44
use OCP\Session\Exceptions\SessionNotAvailableException;
45
46
class AuthSettingsController extends Controller {
47
48
	/** @var IProvider */
49
	private $tokenProvider;
50
51
	/** @var ISession */
52
	private $session;
53
54
	/** @var string */
55
	private $uid;
56
57
	/** @var ISecureRandom */
58
	private $random;
59
60
	/** @var IManager */
61
	private $activityManager;
62
63
	/** @var ILogger */
64
	private $logger;
65
66
	/**
67
	 * @param string $appName
68
	 * @param IRequest $request
69
	 * @param IProvider $tokenProvider
70
	 * @param ISession $session
71
	 * @param ISecureRandom $random
72
	 * @param string|null $userId
73
	 * @param IManager $activityManager
74
	 * @param ILogger $logger
75
	 */
76
	public function __construct(string $appName,
77
								IRequest $request,
78
								IProvider $tokenProvider,
79
								ISession $session,
80
								ISecureRandom $random,
81
								?string $userId,
82
								IManager $activityManager,
83
								ILogger $logger) {
84
		parent::__construct($appName, $request);
85
		$this->tokenProvider = $tokenProvider;
86
		$this->uid = $userId;
87
		$this->session = $session;
88
		$this->random = $random;
89
		$this->activityManager = $activityManager;
90
		$this->logger = $logger;
91
	}
92
93
	/**
94
	 * @NoAdminRequired
95
	 * @NoSubadminRequired
96
	 *
97
	 * @return JSONResponse|array
98
	 */
99
	public function index() {
100
		$tokens = $this->tokenProvider->getTokenByUser($this->uid);
101
102
		try {
103
			$sessionId = $this->session->getId();
104
		} catch (SessionNotAvailableException $ex) {
105
			return $this->getServiceNotAvailableResponse();
106
		}
107
		try {
108
			$sessionToken = $this->tokenProvider->getToken($sessionId);
109
		} catch (InvalidTokenException $ex) {
110
			return $this->getServiceNotAvailableResponse();
111
		}
112
113
		return array_map(function (IToken $token) use ($sessionToken) {
114
			$data = $token->jsonSerialize();
115
			if ($sessionToken->getId() === $token->getId()) {
116
				$data['canDelete'] = false;
117
				$data['current'] = true;
118
			} else {
119
				$data['canDelete'] = true;
120
			}
121
			return $data;
122
		}, $tokens);
123
	}
124
125
	/**
126
	 * @NoAdminRequired
127
	 * @NoSubadminRequired
128
	 * @PasswordConfirmationRequired
129
	 *
130
	 * @param string $name
131
	 * @return JSONResponse
132
	 */
133
	public function create($name) {
134
		try {
135
			$sessionId = $this->session->getId();
136
		} catch (SessionNotAvailableException $ex) {
137
			return $this->getServiceNotAvailableResponse();
138
		}
139
140
		try {
141
			$sessionToken = $this->tokenProvider->getToken($sessionId);
142
			$loginName = $sessionToken->getLoginName();
143
			try {
144
				$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
145
			} catch (PasswordlessTokenException $ex) {
146
				$password = null;
147
			}
148
		} catch (InvalidTokenException $ex) {
149
			return $this->getServiceNotAvailableResponse();
150
		}
151
152
		$token = $this->generateRandomDeviceToken();
153
		$deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN);
154
		$tokenData = $deviceToken->jsonSerialize();
155
		$tokenData['canDelete'] = true;
156
157
		$this->publishActivity(Provider::APP_TOKEN_CREATED, $deviceToken->getId(), $deviceToken->getName());
158
159
		return new JSONResponse([
160
			'token' => $token,
161
			'loginName' => $loginName,
162
			'deviceToken' => $tokenData,
163
		]);
164
	}
165
166
	/**
167
	 * @return JSONResponse
168
	 */
169
	private function getServiceNotAvailableResponse() {
170
		$resp = new JSONResponse();
171
		$resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
172
		return $resp;
173
	}
174
175
	/**
176
	 * Return a 25 digit device password
177
	 *
178
	 * Example: AbCdE-fGhJk-MnPqR-sTwXy-23456
179
	 *
180
	 * @return string
181
	 */
182
	private function generateRandomDeviceToken() {
183
		$groups = [];
184
		for ($i = 0; $i < 5; $i++) {
185
			$groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
186
		}
187
		return implode('-', $groups);
188
	}
189
190
	/**
191
	 * @NoAdminRequired
192
	 * @NoSubadminRequired
193
	 *
194
	 * @param int $id
195
	 * @return array|JSONResponse
196
	 */
197
	public function destroy($id) {
198
		try {
199
			$token = $this->findTokenByIdAndUser($id);
200
		} catch (InvalidTokenException $e) {
201
			return new JSONResponse([], Http::STATUS_NOT_FOUND);
202
		}
203
204
		$this->tokenProvider->invalidateTokenById($this->uid, $token->getId());
205
		$this->publishActivity(Provider::APP_TOKEN_DELETED, $token->getId(), $token->getName());
206
		return [];
207
	}
208
209
	/**
210
	 * @NoAdminRequired
211
	 * @NoSubadminRequired
212
	 *
213
	 * @param int $id
214
	 * @param array $scope
215
	 * @return array|JSONResponse
216
	 */
217
	public function update($id, array $scope) {
218
		try {
219
			$token = $this->findTokenByIdAndUser($id);
220
		} catch (InvalidTokenException $e) {
221
			return new JSONResponse([], Http::STATUS_NOT_FOUND);
222
		}
223
224
		$token->setScope([
225
			'filesystem' => $scope['filesystem']
226
		]);
227
228
		$this->tokenProvider->updateToken($token);
229
		$this->publishActivity(Provider::APP_TOKEN_UPDATED, $token->getId(), $token->getName());
230
		return [];
231
	}
232
233
	/**
234
	 * @param string $subject
235
	 * @param int $id
236
	 * @param string|null $tokenName
237
	 */
238
	private function publishActivity(string $subject, int $id, ?string $tokenName = null): void {
239
		$event = $this->activityManager->generateEvent();
240
		$event->setApp('settings')
241
			->setType('security')
242
			->setAffectedUser($this->uid)
243
			->setAuthor($this->uid)
244
			->setSubject($subject, [$tokenName])
245
			->setObject('app_token', $id, 'App Password');
246
247
		try {
248
			$this->activityManager->publish($event);
249
		} catch (BadMethodCallException $e) {
250
			$this->logger->warning('could not publish activity');
251
			$this->logger->logException($e);
252
		}
253
	}
254
255
	/**
256
	 * Find a token by given id and check if uid for current session belongs to this token
257
	 *
258
	 * @param int $id
259
	 * @return IToken
260
	 * @throws InvalidTokenException
261
	 * @throws \OC\Authentication\Exceptions\ExpiredTokenException
262
	 */
263
	private function findTokenByIdAndUser(int $id): IToken {
264
		$token = $this->tokenProvider->getTokenById($id);
265
		if ($token->getUID() !== $this->uid) {
266
			throw new InvalidTokenException('This token does not belong to you!');
267
		}
268
		return $token;
269
	}
270
}
271