Passed
Push — master ( ba155a...1cfa87 )
by Roeland
10:09
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\INamedToken;
35
use OC\Authentication\Token\IProvider;
36
use OC\Authentication\Token\IToken;
37
use OC\Settings\Activity\Provider;
38
use OCP\Activity\IManager;
39
use OC\Authentication\Token\PublicKeyToken;
40
use OCP\AppFramework\Controller;
41
use OCP\AppFramework\Http\JSONResponse;
42
use OCP\ILogger;
43
use OCP\IRequest;
44
use OCP\ISession;
45
use OCP\Security\ISecureRandom;
46
use OCP\Session\Exceptions\SessionNotAvailableException;
47
48
class AuthSettingsController extends Controller {
49
50
	/** @var IProvider */
51
	private $tokenProvider;
52
53
	/** @var ISession */
54
	private $session;
55
56
	/** @var string */
57
	private $uid;
58
59
	/** @var ISecureRandom */
60
	private $random;
61
62
	/** @var IManager */
63
	private $activityManager;
64
65
	/** @var ILogger */
66
	private $logger;
67
68
	/**
69
	 * @param string $appName
70
	 * @param IRequest $request
71
	 * @param IProvider $tokenProvider
72
	 * @param ISession $session
73
	 * @param ISecureRandom $random
74
	 * @param string|null $userId
75
	 * @param IManager $activityManager
76
	 * @param ILogger $logger
77
	 */
78
	public function __construct(string $appName,
79
								IRequest $request,
80
								IProvider $tokenProvider,
81
								ISession $session,
82
								ISecureRandom $random,
83
								?string $userId,
84
								IManager $activityManager,
85
								ILogger $logger) {
86
		parent::__construct($appName, $request);
87
		$this->tokenProvider = $tokenProvider;
88
		$this->uid = $userId;
89
		$this->session = $session;
90
		$this->random = $random;
91
		$this->activityManager = $activityManager;
92
		$this->logger = $logger;
93
	}
94
95
	/**
96
	 * @NoAdminRequired
97
	 * @NoSubadminRequired
98
	 * @PasswordConfirmationRequired
99
	 *
100
	 * @param string $name
101
	 * @return JSONResponse
102
	 */
103
	public function create($name) {
104
		try {
105
			$sessionId = $this->session->getId();
106
		} catch (SessionNotAvailableException $ex) {
107
			return $this->getServiceNotAvailableResponse();
108
		}
109
110
		try {
111
			$sessionToken = $this->tokenProvider->getToken($sessionId);
112
			$loginName = $sessionToken->getLoginName();
113
			try {
114
				$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
115
			} catch (PasswordlessTokenException $ex) {
116
				$password = null;
117
			}
118
		} catch (InvalidTokenException $ex) {
119
			return $this->getServiceNotAvailableResponse();
120
		}
121
122
		$token = $this->generateRandomDeviceToken();
123
		$deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN);
124
		$tokenData = $deviceToken->jsonSerialize();
125
		$tokenData['canDelete'] = true;
126
		$tokenData['canRename'] = true;
127
128
		$this->publishActivity(Provider::APP_TOKEN_CREATED, $deviceToken->getId(), ['name' => $deviceToken->getName()]);
129
130
		return new JSONResponse([
131
			'token' => $token,
132
			'loginName' => $loginName,
133
			'deviceToken' => $tokenData,
134
		]);
135
	}
136
137
	/**
138
	 * @return JSONResponse
139
	 */
140
	private function getServiceNotAvailableResponse() {
141
		$resp = new JSONResponse();
142
		$resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
143
		return $resp;
144
	}
145
146
	/**
147
	 * Return a 25 digit device password
148
	 *
149
	 * Example: AbCdE-fGhJk-MnPqR-sTwXy-23456
150
	 *
151
	 * @return string
152
	 */
153
	private function generateRandomDeviceToken() {
154
		$groups = [];
155
		for ($i = 0; $i < 5; $i++) {
156
			$groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
157
		}
158
		return implode('-', $groups);
159
	}
160
161
	/**
162
	 * @NoAdminRequired
163
	 * @NoSubadminRequired
164
	 *
165
	 * @param int $id
166
	 * @return array|JSONResponse
167
	 */
168
	public function destroy($id) {
169
		try {
170
			$token = $this->findTokenByIdAndUser($id);
171
		} catch (InvalidTokenException $e) {
172
			return new JSONResponse([], Http::STATUS_NOT_FOUND);
173
		}
174
175
		$this->tokenProvider->invalidateTokenById($this->uid, $token->getId());
176
		$this->publishActivity(Provider::APP_TOKEN_DELETED, $token->getId(), ['name' => $token->getName()]);
177
		return [];
178
	}
179
180
	/**
181
	 * @NoAdminRequired
182
	 * @NoSubadminRequired
183
	 *
184
	 * @param int $id
185
	 * @param array $scope
186
	 * @param string $name
187
	 * @return array|JSONResponse
188
	 */
189
	public function update($id, array $scope, string $name) {
190
		try {
191
			$token = $this->findTokenByIdAndUser($id);
192
		} catch (InvalidTokenException $e) {
193
			return new JSONResponse([], Http::STATUS_NOT_FOUND);
194
		}
195
196
		$currentName = $token->getName();
197
198
		if ($scope !== $token->getScopeAsArray()) {
199
			$token->setScope(['filesystem' => $scope['filesystem']]);
200
			$this->publishActivity($scope['filesystem'] ? Provider::APP_TOKEN_FILESYSTEM_GRANTED : Provider::APP_TOKEN_FILESYSTEM_REVOKED, $token->getId(), ['name' => $currentName]);
201
		}
202
203
		if ($token instanceof INamedToken && $name !== $currentName) {
204
			$token->setName($name);
205
			$this->publishActivity(Provider::APP_TOKEN_RENAMED, $token->getId(), ['name' => $currentName, 'newName' => $name]);
206
		}
207
208
		$this->tokenProvider->updateToken($token);
209
		return [];
210
	}
211
212
	/**
213
	 * @param string $subject
214
	 * @param int $id
215
	 * @param array $parameters
216
	 */
217
	private function publishActivity(string $subject, int $id, array $parameters = []): void {
218
		$event = $this->activityManager->generateEvent();
219
		$event->setApp('settings')
220
			->setType('security')
221
			->setAffectedUser($this->uid)
222
			->setAuthor($this->uid)
223
			->setSubject($subject, $parameters)
224
			->setObject('app_token', $id, 'App Password');
225
226
		try {
227
			$this->activityManager->publish($event);
228
		} catch (BadMethodCallException $e) {
229
			$this->logger->warning('could not publish activity');
230
			$this->logger->logException($e);
231
		}
232
	}
233
234
	/**
235
	 * Find a token by given id and check if uid for current session belongs to this token
236
	 *
237
	 * @param int $id
238
	 * @return IToken
239
	 * @throws InvalidTokenException
240
	 * @throws \OC\Authentication\Exceptions\ExpiredTokenException
241
	 */
242
	private function findTokenByIdAndUser(int $id): IToken {
243
		$token = $this->tokenProvider->getTokenById($id);
244
		if ($token->getUID() !== $this->uid) {
245
			throw new InvalidTokenException('This token does not belong to you!');
246
		}
247
		return $token;
248
	}
249
}
250