Completed
Push — stable8.2 ( b54faa...3a8391 )
by
unknown
37:04
created

UserHooks::initMountPoints()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 * @author Clark Tomlinson <[email protected]>
5
 * @author Thomas Müller <[email protected]>
6
 *
7
 * @copyright Copyright (c) 2015, ownCloud, Inc.
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OCA\Encryption\Hooks;
25
26
27
use OC\Files\Filesystem;
28
use OCP\IUserManager;
29
use OCP\Util as OCUtil;
30
use OCA\Encryption\Hooks\Contracts\IHook;
31
use OCA\Encryption\KeyManager;
32
use OCA\Encryption\Crypto\Crypt;
33
use OCA\Encryption\Users\Setup;
34
use OCP\App;
35
use OCP\ILogger;
36
use OCP\IUserSession;
37
use OCA\Encryption\Util;
38
use OCA\Encryption\Session;
39
use OCA\Encryption\Recovery;
40
41
class UserHooks implements IHook {
42
	/**
43
	 * @var KeyManager
44
	 */
45
	private $keyManager;
46
	/**
47
	 * @var IUserManager
48
	 */
49
	private $userManager;
50
	/**
51
	 * @var ILogger
52
	 */
53
	private $logger;
54
	/**
55
	 * @var Setup
56
	 */
57
	private $userSetup;
58
	/**
59
	 * @var IUserSession
60
	 */
61
	private $user;
62
	/**
63
	 * @var Util
64
	 */
65
	private $util;
66
	/**
67
	 * @var Session
68
	 */
69
	private $session;
70
	/**
71
	 * @var Recovery
72
	 */
73
	private $recovery;
74
	/**
75
	 * @var Crypt
76
	 */
77
	private $crypt;
78
79
	/**
80
	 * UserHooks constructor.
81
	 *
82
	 * @param KeyManager $keyManager
83
	 * @param IUserManager $userManager
84
	 * @param ILogger $logger
85
	 * @param Setup $userSetup
86
	 * @param IUserSession $user
87
	 * @param Util $util
88
	 * @param Session $session
89
	 * @param Crypt $crypt
90
	 * @param Recovery $recovery
91 9
	 */
92 View Code Duplication
	public function __construct(KeyManager $keyManager,
93
								IUserManager $userManager,
94
								ILogger $logger,
95
								Setup $userSetup,
96
								IUserSession $user,
97
								Util $util,
98
								Session $session,
99
								Crypt $crypt,
100
								Recovery $recovery) {
101 9
102 9
		$this->keyManager = $keyManager;
103 9
		$this->userManager = $userManager;
104 9
		$this->logger = $logger;
105 9
		$this->userSetup = $userSetup;
106 9
		$this->user = $user;
107 9
		$this->util = $util;
108 9
		$this->session = $session;
109 9
		$this->recovery = $recovery;
110 9
		$this->crypt = $crypt;
111
	}
112
113
	/**
114
	 * Connects Hooks
115
	 *
116
	 * @return null
117
	 */
118
	public function addHooks() {
119
		OCUtil::connectHook('OC_User', 'post_login', $this, 'login');
120
		OCUtil::connectHook('OC_User', 'logout', $this, 'logout');
121
		OCUtil::connectHook('OC_User',
122
			'post_setPassword',
123
			$this,
124
			'setPassphrase');
125
		OCUtil::connectHook('OC_User',
126
			'pre_setPassword',
127
			$this,
128
			'preSetPassphrase');
129
		OCUtil::connectHook('OC_User',
130
			'post_createUser',
131
			$this,
132
			'postCreateUser');
133
		OCUtil::connectHook('OC_User',
134
			'post_deleteUser',
135
			$this,
136
			'postDeleteUser');
137
	}
138
139
140
	/**
141
	 * Startup encryption backend upon user login
142
	 *
143
	 * @note This method should never be called for users using client side encryption
144
	 * @param array $params
145
	 * @return bool
146 1
	 */
147
	public function login($params) {
148 1
149
		if (!App::isEnabled('encryption')) {
150
			return true;
151
		}
152
153 1
		// ensure filesystem is loaded
154
		if (!\OC\Files\Filesystem::$loaded) {
155
			\OC_Util::setupFS($params['uid']);
156
		}
157
158 1
		// setup user, if user not ready force relogin
159 1
		if (!$this->userSetup->setupUser($params['uid'], $params['password'])) {
160
			return false;
161
		}
162 1
163 1
		$this->keyManager->init($params['uid'], $params['password']);
164
	}
165
166
	/**
167
	 * remove keys from session during logout
168 1
	 */
169 1
	public function logout() {
170 1
		$this->session->clear();
171
	}
172
173
	/**
174
	 * setup encryption backend upon user created
175
	 *
176
	 * @note This method should never be called for users using client side encryption
177
	 * @param array $params
178 1
	 */
179
	public function postCreateUser($params) {
180 1
181 1
		if (App::isEnabled('encryption')) {
182 1
			$this->userSetup->setupUser($params['uid'], $params['password']);
183 1
		}
184
	}
185
186
	/**
187
	 * cleanup encryption backend upon user deleted
188
	 *
189
	 * @param array $params : uid, password
190
	 * @note This method should never be called for users using client side encryption
191 1
	 */
192
	public function postDeleteUser($params) {
193 1
194 1
		if (App::isEnabled('encryption')) {
195 1
			$this->keyManager->deletePublicKey($params['uid']);
196 1
		}
197
	}
198
199
	/**
200
	 * If the password can't be changed within ownCloud, than update the key password in advance.
201
	 *
202
	 * @param array $params : uid, password
203
	 * @return bool
204 2
	 */
205 2
	public function preSetPassphrase($params) {
206
		if (App::isEnabled('encryption')) {
207 2
208
			$user = $this->userManager->get($params['uid']);
209 2
210 1
			if ($user && !$user->canChangePassword()) {
211 1
				$this->setPassphrase($params);
212 2
			}
213 2
		}
214
	}
215
216
	/**
217
	 * Change a user's encryption passphrase
218
	 *
219
	 * @param array $params keys: uid, password
220
	 * @return bool
221 2
	 */
222
	public function setPassphrase($params) {
223
224 2
		// Get existing decrypted private key
225 2
		$privateKey = $this->session->getPrivateKey();
226
		$user = $this->user->getUser();
227
228 2
		// current logged in user changes his own password
229
		if ($user && $params['uid'] === $user->getUID() && $privateKey) {
230
231 1
			// Encrypt private key with new user pwd as passphrase
232
			$encryptedPrivateKey = $this->crypt->encryptPrivateKey($privateKey, $params['password'], $params['uid']);
233
234 1
			// Save private key
235 1
			if ($encryptedPrivateKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encryptedPrivateKey of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
236 1
				$this->keyManager->setPrivateKey($this->user->getUser()->getUID(),
237 1
					$this->crypt->generateHeader() . $encryptedPrivateKey);
238
			} else {
239
				$this->logger->error('Encryption could not update users encryption password');
240
			}
241
242
			// NOTE: Session does not need to be updated as the
243
			// private key has not changed, only the passphrase
244 1
			// used to decrypt it has changed
245 2
		} else { // admin changed the password for a different user, create new keys and re-encrypt file keys
246 2
			$user = $params['uid'];
247
			$this->initMountPoints($user);
248
			$recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
249
250
			// we generate new keys if...
251
			// ...we have a recovery password and the user enabled the recovery key
252
			// ...encryption was activated for the first time (no keys exists)
253 2
			// ...the user doesn't have any files
254 2
			if (
255 2
				($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword)
256 2
				|| !$this->keyManager->userHasKeys($user)
257
				|| !$this->util->userHasFiles($user)
258
			) {
259
260
				// backup old keys
261 2
				//$this->backupAllKeys('recovery');
262
263 2
				$newUserPassword = $params['password'];
264
265
				$keyPair = $this->crypt->createKeyPair();
266 2
267
				// Save public key
268
				$this->keyManager->setPublicKey($user, $keyPair['publicKey']);
269 2
270
				// Encrypt private key with new password
271 2
				$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $newUserPassword, $user);
272 1
273
				if ($encryptedKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encryptedKey of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
274 1
					$this->keyManager->setPrivateKey($user, $this->crypt->generateHeader() . $encryptedKey);
275 1
276 1
					if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
277 1
						$this->recovery->recoverUsersFiles($recoveryPassword, $user);
278 1
					}
279
				} else {
280 2
					$this->logger->error('Encryption Could not update users encryption password');
281
				}
282 2
			}
283
		}
284
	}
285
286
	/**
287
	 * init mount points for given user
288
	 *
289
	 * @param string $user
290
	 * @throws \OC\User\NoUserException
291 1
	 */
292 1
	protected function initMountPoints($user) {
293
		Filesystem::initMountPoints($user);
294 1
	}
295 1
296 1
297
	/**
298
	 * after password reset we create a new key pair for the user
299
	 *
300
	 * @param array $params
301
	 */
302
	public function postPasswordReset($params) {
303
		$password = $params['password'];
304
305
		$this->keyManager->replaceUserKeys($params['uid']);
306
		$this->userSetup->setupServerSide($params['uid'], $password);
307
	}
308
}
309