Completed
Pull Request — master (#5174)
by Björn
17:02
created
apps/encryption/lib/KeyManager.php 2 patches
Indentation   +681 added lines, -681 removed lines patch added patch discarded remove patch
@@ -38,685 +38,685 @@
 block discarded – undo
38 38
 
39 39
 class KeyManager {
40 40
 
41
-	/**
42
-	 * @var Session
43
-	 */
44
-	protected $session;
45
-	/**
46
-	 * @var IStorage
47
-	 */
48
-	private $keyStorage;
49
-	/**
50
-	 * @var Crypt
51
-	 */
52
-	private $crypt;
53
-	/**
54
-	 * @var string
55
-	 */
56
-	private $recoveryKeyId;
57
-	/**
58
-	 * @var string
59
-	 */
60
-	private $publicShareKeyId;
61
-	/**
62
-	 * @var string
63
-	 */
64
-	private $masterKeyId;
65
-	/**
66
-	 * @var string UserID
67
-	 */
68
-	private $keyId;
69
-	/**
70
-	 * @var string
71
-	 */
72
-	private $publicKeyId = 'publicKey';
73
-	/**
74
-	 * @var string
75
-	 */
76
-	private $privateKeyId = 'privateKey';
77
-
78
-	/**
79
-	 * @var string
80
-	 */
81
-	private $shareKeyId = 'shareKey';
82
-
83
-	/**
84
-	 * @var string
85
-	 */
86
-	private $fileKeyId = 'fileKey';
87
-	/**
88
-	 * @var IConfig
89
-	 */
90
-	private $config;
91
-	/**
92
-	 * @var ILogger
93
-	 */
94
-	private $log;
95
-	/**
96
-	 * @var Util
97
-	 */
98
-	private $util;
99
-
100
-	/**
101
-	 * @param IStorage $keyStorage
102
-	 * @param Crypt $crypt
103
-	 * @param IConfig $config
104
-	 * @param IUserSession $userSession
105
-	 * @param Session $session
106
-	 * @param ILogger $log
107
-	 * @param Util $util
108
-	 */
109
-	public function __construct(
110
-		IStorage $keyStorage,
111
-		Crypt $crypt,
112
-		IConfig $config,
113
-		IUserSession $userSession,
114
-		Session $session,
115
-		ILogger $log,
116
-		Util $util
117
-	) {
118
-
119
-		$this->util = $util;
120
-		$this->session = $session;
121
-		$this->keyStorage = $keyStorage;
122
-		$this->crypt = $crypt;
123
-		$this->config = $config;
124
-		$this->log = $log;
125
-
126
-		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127
-			'recoveryKeyId');
128
-		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
-			$this->config->setAppValue('encryption',
131
-				'recoveryKeyId',
132
-				$this->recoveryKeyId);
133
-		}
134
-
135
-		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136
-			'publicShareKeyId');
137
-		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
-			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
-		}
141
-
142
-		$this->masterKeyId = $this->config->getAppValue('encryption',
143
-			'masterKeyId');
144
-		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
-			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
-		}
148
-
149
-		$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
-		$this->log = $log;
151
-	}
152
-
153
-	/**
154
-	 * check if key pair for public link shares exists, if not we create one
155
-	 */
156
-	public function validateShareKey() {
157
-		$shareKey = $this->getPublicShareKey();
158
-		if (empty($shareKey)) {
159
-			$keyPair = $this->crypt->createKeyPair();
160
-
161
-			// Save public key
162
-			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
-				Encryption::ID);
165
-
166
-			// Encrypt private key empty passphrase
167
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
-			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * check if a key pair for the master key exists, if not we create one
175
-	 */
176
-	public function validateMasterKey() {
177
-
178
-		if ($this->util->isMasterKeyEnabled() === false) {
179
-			return;
180
-		}
181
-
182
-		$publicMasterKey = $this->getPublicMasterKey();
183
-		if (empty($publicMasterKey)) {
184
-			$keyPair = $this->crypt->createKeyPair();
185
-
186
-			// Save public key
187
-			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
-				Encryption::ID);
190
-
191
-			// Encrypt private key with system password
192
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
-			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
-		}
196
-
197
-		if (!$this->session->isPrivateKeySet()) {
198
-			$masterKey = $this->getSystemPrivateKey($this->masterKeyId);
199
-			$decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
200
-			$this->session->setPrivateKey($decryptedMasterKey);
201
-		}
202
-
203
-		// after the encryption key is available we are ready to go
204
-		$this->session->setStatus(Session::INIT_SUCCESSFUL);
205
-	}
206
-
207
-	/**
208
-	 * @return bool
209
-	 */
210
-	public function recoveryKeyExists() {
211
-		$key = $this->getRecoveryKey();
212
-		return (!empty($key));
213
-	}
214
-
215
-	/**
216
-	 * get recovery key
217
-	 *
218
-	 * @return string
219
-	 */
220
-	public function getRecoveryKey() {
221
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
222
-	}
223
-
224
-	/**
225
-	 * get recovery key ID
226
-	 *
227
-	 * @return string
228
-	 */
229
-	public function getRecoveryKeyId() {
230
-		return $this->recoveryKeyId;
231
-	}
232
-
233
-	/**
234
-	 * @param string $password
235
-	 * @return bool
236
-	 */
237
-	public function checkRecoveryPassword($password) {
238
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
239
-		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240
-
241
-		if ($decryptedRecoveryKey) {
242
-			return true;
243
-		}
244
-		return false;
245
-	}
246
-
247
-	/**
248
-	 * @param string $uid
249
-	 * @param string $password
250
-	 * @param string $keyPair
251
-	 * @return bool
252
-	 */
253
-	public function storeKeyPair($uid, $password, $keyPair) {
254
-		// Save Public Key
255
-		$this->setPublicKey($uid, $keyPair['publicKey']);
256
-
257
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
258
-
259
-		$header = $this->crypt->generateHeader();
260
-
261
-		if ($encryptedKey) {
262
-			$this->setPrivateKey($uid, $header . $encryptedKey);
263
-			return true;
264
-		}
265
-		return false;
266
-	}
267
-
268
-	/**
269
-	 * @param string $password
270
-	 * @param array $keyPair
271
-	 * @return bool
272
-	 */
273
-	public function setRecoveryKey($password, $keyPair) {
274
-		// Save Public Key
275
-		$this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
276
-			'.publicKey',
277
-			$keyPair['publicKey'],
278
-			Encryption::ID);
279
-
280
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
281
-		$header = $this->crypt->generateHeader();
282
-
283
-		if ($encryptedKey) {
284
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
285
-			return true;
286
-		}
287
-		return false;
288
-	}
289
-
290
-	/**
291
-	 * @param $userId
292
-	 * @param $key
293
-	 * @return bool
294
-	 */
295
-	public function setPublicKey($userId, $key) {
296
-		return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
297
-	}
298
-
299
-	/**
300
-	 * @param $userId
301
-	 * @param string $key
302
-	 * @return bool
303
-	 */
304
-	public function setPrivateKey($userId, $key) {
305
-		return $this->keyStorage->setUserKey($userId,
306
-			$this->privateKeyId,
307
-			$key,
308
-			Encryption::ID);
309
-	}
310
-
311
-	/**
312
-	 * write file key to key storage
313
-	 *
314
-	 * @param string $path
315
-	 * @param string $key
316
-	 * @return boolean
317
-	 */
318
-	public function setFileKey($path, $key) {
319
-		return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
320
-	}
321
-
322
-	/**
323
-	 * set all file keys (the file key and the corresponding share keys)
324
-	 *
325
-	 * @param string $path
326
-	 * @param array $keys
327
-	 */
328
-	public function setAllFileKeys($path, $keys) {
329
-		$this->setFileKey($path, $keys['data']);
330
-		foreach ($keys['keys'] as $uid => $keyFile) {
331
-			$this->setShareKey($path, $uid, $keyFile);
332
-		}
333
-	}
334
-
335
-	/**
336
-	 * write share key to the key storage
337
-	 *
338
-	 * @param string $path
339
-	 * @param string $uid
340
-	 * @param string $key
341
-	 * @return boolean
342
-	 */
343
-	public function setShareKey($path, $uid, $key) {
344
-		$keyId = $uid . '.' . $this->shareKeyId;
345
-		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346
-	}
347
-
348
-	/**
349
-	 * Decrypt private key and store it
350
-	 *
351
-	 * @param string $uid user id
352
-	 * @param string $passPhrase users password
353
-	 * @return boolean
354
-	 */
355
-	public function init($uid, $passPhrase) {
356
-
357
-		$this->session->setStatus(Session::INIT_EXECUTED);
358
-
359
-		try {
360
-			if($this->util->isMasterKeyEnabled()) {
361
-				$uid = $this->getMasterKeyId();
362
-				$passPhrase = $this->getMasterKeyPassword();
363
-				$privateKey = $this->getSystemPrivateKey($uid);
364
-			} else {
365
-				$privateKey = $this->getPrivateKey($uid);
366
-			}
367
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
368
-		} catch (PrivateKeyMissingException $e) {
369
-			return false;
370
-		} catch (DecryptionFailedException $e) {
371
-			return false;
372
-		} catch (\Exception $e) {
373
-			$this->log->warning(
374
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
375
-				'Assume password change on the user back-end. Error message: '
376
-				. $e->getMessage()
377
-			);
378
-			return false;
379
-		}
380
-
381
-		if ($privateKey) {
382
-			$this->session->setPrivateKey($privateKey);
383
-			$this->session->setStatus(Session::INIT_SUCCESSFUL);
384
-			return true;
385
-		}
386
-
387
-		return false;
388
-	}
389
-
390
-	/**
391
-	 * @param $userId
392
-	 * @return string
393
-	 * @throws PrivateKeyMissingException
394
-	 */
395
-	public function getPrivateKey($userId) {
396
-		$privateKey = $this->keyStorage->getUserKey($userId,
397
-			$this->privateKeyId, Encryption::ID);
398
-
399
-		if (strlen($privateKey) !== 0) {
400
-			return $privateKey;
401
-		}
402
-		throw new PrivateKeyMissingException($userId);
403
-	}
404
-
405
-	/**
406
-	 * @param string $path
407
-	 * @param $uid
408
-	 * @return string
409
-	 */
410
-	public function getFileKey($path, $uid) {
411
-		if ($uid === '') {
412
-			$uid = null;
413
-		}
414
-		$publicAccess = is_null($uid);
415
-		$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
416
-
417
-		if (empty($encryptedFileKey)) {
418
-			return '';
419
-		}
420
-
421
-		if ($this->util->isMasterKeyEnabled()) {
422
-			$uid = $this->getMasterKeyId();
423
-			$shareKey = $this->getShareKey($path, $uid);
424
-			if ($publicAccess) {
425
-				$privateKey = $this->getSystemPrivateKey($uid);
426
-				$privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
427
-			} else {
428
-				// when logged in, the master key is already decrypted in the session
429
-				$privateKey = $this->session->getPrivateKey();
430
-			}
431
-		} else if ($publicAccess) {
432
-			// use public share key for public links
433
-			$uid = $this->getPublicShareKeyId();
434
-			$shareKey = $this->getShareKey($path, $uid);
435
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
436
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
437
-		} else {
438
-			$shareKey = $this->getShareKey($path, $uid);
439
-			$privateKey = $this->session->getPrivateKey();
440
-		}
441
-
442
-		if ($encryptedFileKey && $shareKey && $privateKey) {
443
-			return $this->crypt->multiKeyDecrypt($encryptedFileKey,
444
-				$shareKey,
445
-				$privateKey);
446
-		}
447
-
448
-		return '';
449
-	}
450
-
451
-	/**
452
-	 * Get the current version of a file
453
-	 *
454
-	 * @param string $path
455
-	 * @param View $view
456
-	 * @return int
457
-	 */
458
-	public function getVersion($path, View $view) {
459
-		$fileInfo = $view->getFileInfo($path);
460
-		if($fileInfo === false) {
461
-			return 0;
462
-		}
463
-		return $fileInfo->getEncryptedVersion();
464
-	}
465
-
466
-	/**
467
-	 * Set the current version of a file
468
-	 *
469
-	 * @param string $path
470
-	 * @param int $version
471
-	 * @param View $view
472
-	 */
473
-	public function setVersion($path, $version, View $view) {
474
-		$fileInfo= $view->getFileInfo($path);
475
-
476
-		if($fileInfo !== false) {
477
-			$cache = $fileInfo->getStorage()->getCache();
478
-			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479
-		}
480
-	}
481
-
482
-	/**
483
-	 * get the encrypted file key
484
-	 *
485
-	 * @param string $path
486
-	 * @return string
487
-	 */
488
-	public function getEncryptedFileKey($path) {
489
-		$encryptedFileKey = $this->keyStorage->getFileKey($path,
490
-			$this->fileKeyId, Encryption::ID);
491
-
492
-		return $encryptedFileKey;
493
-	}
494
-
495
-	/**
496
-	 * delete share key
497
-	 *
498
-	 * @param string $path
499
-	 * @param string $keyId
500
-	 * @return boolean
501
-	 */
502
-	public function deleteShareKey($path, $keyId) {
503
-		return $this->keyStorage->deleteFileKey(
504
-			$path,
505
-			$keyId . '.' . $this->shareKeyId,
506
-			Encryption::ID);
507
-	}
508
-
509
-
510
-	/**
511
-	 * @param $path
512
-	 * @param $uid
513
-	 * @return mixed
514
-	 */
515
-	public function getShareKey($path, $uid) {
516
-		$keyId = $uid . '.' . $this->shareKeyId;
517
-		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518
-	}
519
-
520
-	/**
521
-	 * check if user has a private and a public key
522
-	 *
523
-	 * @param string $userId
524
-	 * @return bool
525
-	 * @throws PrivateKeyMissingException
526
-	 * @throws PublicKeyMissingException
527
-	 */
528
-	public function userHasKeys($userId) {
529
-		$privateKey = $publicKey = true;
530
-		$exception = null;
531
-
532
-		try {
533
-			$this->getPrivateKey($userId);
534
-		} catch (PrivateKeyMissingException $e) {
535
-			$privateKey = false;
536
-			$exception = $e;
537
-		}
538
-		try {
539
-			$this->getPublicKey($userId);
540
-		} catch (PublicKeyMissingException $e) {
541
-			$publicKey = false;
542
-			$exception = $e;
543
-		}
544
-
545
-		if ($privateKey && $publicKey) {
546
-			return true;
547
-		} elseif (!$privateKey && !$publicKey) {
548
-			return false;
549
-		} else {
550
-			throw $exception;
551
-		}
552
-	}
553
-
554
-	/**
555
-	 * @param $userId
556
-	 * @return mixed
557
-	 * @throws PublicKeyMissingException
558
-	 */
559
-	public function getPublicKey($userId) {
560
-		$publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
561
-
562
-		if (strlen($publicKey) !== 0) {
563
-			return $publicKey;
564
-		}
565
-		throw new PublicKeyMissingException($userId);
566
-	}
567
-
568
-	public function getPublicShareKeyId() {
569
-		return $this->publicShareKeyId;
570
-	}
571
-
572
-	/**
573
-	 * get public key for public link shares
574
-	 *
575
-	 * @return string
576
-	 */
577
-	public function getPublicShareKey() {
578
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
579
-	}
580
-
581
-	/**
582
-	 * @param string $purpose
583
-	 * @param string $uid
584
-	 */
585
-	public function backupUserKeys($purpose, $uid) {
586
-		$this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
587
-	}
588
-
589
-	/**
590
-	 * creat a backup of the users private and public key and then  delete it
591
-	 *
592
-	 * @param string $uid
593
-	 */
594
-	public function deleteUserKeys($uid) {
595
-		$this->deletePublicKey($uid);
596
-		$this->deletePrivateKey($uid);
597
-	}
598
-
599
-	/**
600
-	 * @param $uid
601
-	 * @return bool
602
-	 */
603
-	public function deletePublicKey($uid) {
604
-		return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
605
-	}
606
-
607
-	/**
608
-	 * @param string $uid
609
-	 * @return bool
610
-	 */
611
-	private function deletePrivateKey($uid) {
612
-		return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
613
-	}
614
-
615
-	/**
616
-	 * @param string $path
617
-	 * @return bool
618
-	 */
619
-	public function deleteAllFileKeys($path) {
620
-		return $this->keyStorage->deleteAllFileKeys($path);
621
-	}
622
-
623
-	/**
624
-	 * @param array $userIds
625
-	 * @return array
626
-	 * @throws PublicKeyMissingException
627
-	 */
628
-	public function getPublicKeys(array $userIds) {
629
-		$keys = [];
630
-
631
-		foreach ($userIds as $userId) {
632
-			try {
633
-				$keys[$userId] = $this->getPublicKey($userId);
634
-			} catch (PublicKeyMissingException $e) {
635
-				continue;
636
-			}
637
-		}
638
-
639
-		return $keys;
640
-
641
-	}
642
-
643
-	/**
644
-	 * @param string $keyId
645
-	 * @return string returns openssl key
646
-	 */
647
-	public function getSystemPrivateKey($keyId) {
648
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
649
-	}
650
-
651
-	/**
652
-	 * @param string $keyId
653
-	 * @param string $key
654
-	 * @return string returns openssl key
655
-	 */
656
-	public function setSystemPrivateKey($keyId, $key) {
657
-		return $this->keyStorage->setSystemUserKey(
658
-			$keyId . '.' . $this->privateKeyId,
659
-			$key,
660
-			Encryption::ID);
661
-	}
662
-
663
-	/**
664
-	 * add system keys such as the public share key and the recovery key
665
-	 *
666
-	 * @param array $accessList
667
-	 * @param array $publicKeys
668
-	 * @param string $uid
669
-	 * @return array
670
-	 * @throws PublicKeyMissingException
671
-	 */
672
-	public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
673
-		if (!empty($accessList['public'])) {
674
-			$publicShareKey = $this->getPublicShareKey();
675
-			if (empty($publicShareKey)) {
676
-				throw new PublicKeyMissingException($this->getPublicShareKeyId());
677
-			}
678
-			$publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
679
-		}
680
-
681
-		if ($this->recoveryKeyExists() &&
682
-			$this->util->isRecoveryEnabledForUser($uid)) {
683
-
684
-			$publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
685
-		}
686
-
687
-		return $publicKeys;
688
-	}
689
-
690
-	/**
691
-	 * get master key password
692
-	 *
693
-	 * @return string
694
-	 * @throws \Exception
695
-	 */
696
-	public function getMasterKeyPassword() {
697
-		$password = $this->config->getSystemValue('secret');
698
-		if (empty($password)){
699
-			throw new \Exception('Can not get secret from Nextcloud instance');
700
-		}
701
-
702
-		return $password;
703
-	}
704
-
705
-	/**
706
-	 * return master key id
707
-	 *
708
-	 * @return string
709
-	 */
710
-	public function getMasterKeyId() {
711
-		return $this->masterKeyId;
712
-	}
713
-
714
-	/**
715
-	 * get public master key
716
-	 *
717
-	 * @return string
718
-	 */
719
-	public function getPublicMasterKey() {
720
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
721
-	}
41
+    /**
42
+     * @var Session
43
+     */
44
+    protected $session;
45
+    /**
46
+     * @var IStorage
47
+     */
48
+    private $keyStorage;
49
+    /**
50
+     * @var Crypt
51
+     */
52
+    private $crypt;
53
+    /**
54
+     * @var string
55
+     */
56
+    private $recoveryKeyId;
57
+    /**
58
+     * @var string
59
+     */
60
+    private $publicShareKeyId;
61
+    /**
62
+     * @var string
63
+     */
64
+    private $masterKeyId;
65
+    /**
66
+     * @var string UserID
67
+     */
68
+    private $keyId;
69
+    /**
70
+     * @var string
71
+     */
72
+    private $publicKeyId = 'publicKey';
73
+    /**
74
+     * @var string
75
+     */
76
+    private $privateKeyId = 'privateKey';
77
+
78
+    /**
79
+     * @var string
80
+     */
81
+    private $shareKeyId = 'shareKey';
82
+
83
+    /**
84
+     * @var string
85
+     */
86
+    private $fileKeyId = 'fileKey';
87
+    /**
88
+     * @var IConfig
89
+     */
90
+    private $config;
91
+    /**
92
+     * @var ILogger
93
+     */
94
+    private $log;
95
+    /**
96
+     * @var Util
97
+     */
98
+    private $util;
99
+
100
+    /**
101
+     * @param IStorage $keyStorage
102
+     * @param Crypt $crypt
103
+     * @param IConfig $config
104
+     * @param IUserSession $userSession
105
+     * @param Session $session
106
+     * @param ILogger $log
107
+     * @param Util $util
108
+     */
109
+    public function __construct(
110
+        IStorage $keyStorage,
111
+        Crypt $crypt,
112
+        IConfig $config,
113
+        IUserSession $userSession,
114
+        Session $session,
115
+        ILogger $log,
116
+        Util $util
117
+    ) {
118
+
119
+        $this->util = $util;
120
+        $this->session = $session;
121
+        $this->keyStorage = $keyStorage;
122
+        $this->crypt = $crypt;
123
+        $this->config = $config;
124
+        $this->log = $log;
125
+
126
+        $this->recoveryKeyId = $this->config->getAppValue('encryption',
127
+            'recoveryKeyId');
128
+        if (empty($this->recoveryKeyId)) {
129
+            $this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
+            $this->config->setAppValue('encryption',
131
+                'recoveryKeyId',
132
+                $this->recoveryKeyId);
133
+        }
134
+
135
+        $this->publicShareKeyId = $this->config->getAppValue('encryption',
136
+            'publicShareKeyId');
137
+        if (empty($this->publicShareKeyId)) {
138
+            $this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
+            $this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
+        }
141
+
142
+        $this->masterKeyId = $this->config->getAppValue('encryption',
143
+            'masterKeyId');
144
+        if (empty($this->masterKeyId)) {
145
+            $this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
+            $this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
+        }
148
+
149
+        $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
+        $this->log = $log;
151
+    }
152
+
153
+    /**
154
+     * check if key pair for public link shares exists, if not we create one
155
+     */
156
+    public function validateShareKey() {
157
+        $shareKey = $this->getPublicShareKey();
158
+        if (empty($shareKey)) {
159
+            $keyPair = $this->crypt->createKeyPair();
160
+
161
+            // Save public key
162
+            $this->keyStorage->setSystemUserKey(
163
+                $this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
+                Encryption::ID);
165
+
166
+            // Encrypt private key empty passphrase
167
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
+            $header = $this->crypt->generateHeader();
169
+            $this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
+        }
171
+    }
172
+
173
+    /**
174
+     * check if a key pair for the master key exists, if not we create one
175
+     */
176
+    public function validateMasterKey() {
177
+
178
+        if ($this->util->isMasterKeyEnabled() === false) {
179
+            return;
180
+        }
181
+
182
+        $publicMasterKey = $this->getPublicMasterKey();
183
+        if (empty($publicMasterKey)) {
184
+            $keyPair = $this->crypt->createKeyPair();
185
+
186
+            // Save public key
187
+            $this->keyStorage->setSystemUserKey(
188
+                $this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
+                Encryption::ID);
190
+
191
+            // Encrypt private key with system password
192
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
+            $header = $this->crypt->generateHeader();
194
+            $this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
+        }
196
+
197
+        if (!$this->session->isPrivateKeySet()) {
198
+            $masterKey = $this->getSystemPrivateKey($this->masterKeyId);
199
+            $decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
200
+            $this->session->setPrivateKey($decryptedMasterKey);
201
+        }
202
+
203
+        // after the encryption key is available we are ready to go
204
+        $this->session->setStatus(Session::INIT_SUCCESSFUL);
205
+    }
206
+
207
+    /**
208
+     * @return bool
209
+     */
210
+    public function recoveryKeyExists() {
211
+        $key = $this->getRecoveryKey();
212
+        return (!empty($key));
213
+    }
214
+
215
+    /**
216
+     * get recovery key
217
+     *
218
+     * @return string
219
+     */
220
+    public function getRecoveryKey() {
221
+        return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
222
+    }
223
+
224
+    /**
225
+     * get recovery key ID
226
+     *
227
+     * @return string
228
+     */
229
+    public function getRecoveryKeyId() {
230
+        return $this->recoveryKeyId;
231
+    }
232
+
233
+    /**
234
+     * @param string $password
235
+     * @return bool
236
+     */
237
+    public function checkRecoveryPassword($password) {
238
+        $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
239
+        $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240
+
241
+        if ($decryptedRecoveryKey) {
242
+            return true;
243
+        }
244
+        return false;
245
+    }
246
+
247
+    /**
248
+     * @param string $uid
249
+     * @param string $password
250
+     * @param string $keyPair
251
+     * @return bool
252
+     */
253
+    public function storeKeyPair($uid, $password, $keyPair) {
254
+        // Save Public Key
255
+        $this->setPublicKey($uid, $keyPair['publicKey']);
256
+
257
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
258
+
259
+        $header = $this->crypt->generateHeader();
260
+
261
+        if ($encryptedKey) {
262
+            $this->setPrivateKey($uid, $header . $encryptedKey);
263
+            return true;
264
+        }
265
+        return false;
266
+    }
267
+
268
+    /**
269
+     * @param string $password
270
+     * @param array $keyPair
271
+     * @return bool
272
+     */
273
+    public function setRecoveryKey($password, $keyPair) {
274
+        // Save Public Key
275
+        $this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
276
+            '.publicKey',
277
+            $keyPair['publicKey'],
278
+            Encryption::ID);
279
+
280
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
281
+        $header = $this->crypt->generateHeader();
282
+
283
+        if ($encryptedKey) {
284
+            $this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
285
+            return true;
286
+        }
287
+        return false;
288
+    }
289
+
290
+    /**
291
+     * @param $userId
292
+     * @param $key
293
+     * @return bool
294
+     */
295
+    public function setPublicKey($userId, $key) {
296
+        return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
297
+    }
298
+
299
+    /**
300
+     * @param $userId
301
+     * @param string $key
302
+     * @return bool
303
+     */
304
+    public function setPrivateKey($userId, $key) {
305
+        return $this->keyStorage->setUserKey($userId,
306
+            $this->privateKeyId,
307
+            $key,
308
+            Encryption::ID);
309
+    }
310
+
311
+    /**
312
+     * write file key to key storage
313
+     *
314
+     * @param string $path
315
+     * @param string $key
316
+     * @return boolean
317
+     */
318
+    public function setFileKey($path, $key) {
319
+        return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
320
+    }
321
+
322
+    /**
323
+     * set all file keys (the file key and the corresponding share keys)
324
+     *
325
+     * @param string $path
326
+     * @param array $keys
327
+     */
328
+    public function setAllFileKeys($path, $keys) {
329
+        $this->setFileKey($path, $keys['data']);
330
+        foreach ($keys['keys'] as $uid => $keyFile) {
331
+            $this->setShareKey($path, $uid, $keyFile);
332
+        }
333
+    }
334
+
335
+    /**
336
+     * write share key to the key storage
337
+     *
338
+     * @param string $path
339
+     * @param string $uid
340
+     * @param string $key
341
+     * @return boolean
342
+     */
343
+    public function setShareKey($path, $uid, $key) {
344
+        $keyId = $uid . '.' . $this->shareKeyId;
345
+        return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346
+    }
347
+
348
+    /**
349
+     * Decrypt private key and store it
350
+     *
351
+     * @param string $uid user id
352
+     * @param string $passPhrase users password
353
+     * @return boolean
354
+     */
355
+    public function init($uid, $passPhrase) {
356
+
357
+        $this->session->setStatus(Session::INIT_EXECUTED);
358
+
359
+        try {
360
+            if($this->util->isMasterKeyEnabled()) {
361
+                $uid = $this->getMasterKeyId();
362
+                $passPhrase = $this->getMasterKeyPassword();
363
+                $privateKey = $this->getSystemPrivateKey($uid);
364
+            } else {
365
+                $privateKey = $this->getPrivateKey($uid);
366
+            }
367
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
368
+        } catch (PrivateKeyMissingException $e) {
369
+            return false;
370
+        } catch (DecryptionFailedException $e) {
371
+            return false;
372
+        } catch (\Exception $e) {
373
+            $this->log->warning(
374
+                'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
375
+                'Assume password change on the user back-end. Error message: '
376
+                . $e->getMessage()
377
+            );
378
+            return false;
379
+        }
380
+
381
+        if ($privateKey) {
382
+            $this->session->setPrivateKey($privateKey);
383
+            $this->session->setStatus(Session::INIT_SUCCESSFUL);
384
+            return true;
385
+        }
386
+
387
+        return false;
388
+    }
389
+
390
+    /**
391
+     * @param $userId
392
+     * @return string
393
+     * @throws PrivateKeyMissingException
394
+     */
395
+    public function getPrivateKey($userId) {
396
+        $privateKey = $this->keyStorage->getUserKey($userId,
397
+            $this->privateKeyId, Encryption::ID);
398
+
399
+        if (strlen($privateKey) !== 0) {
400
+            return $privateKey;
401
+        }
402
+        throw new PrivateKeyMissingException($userId);
403
+    }
404
+
405
+    /**
406
+     * @param string $path
407
+     * @param $uid
408
+     * @return string
409
+     */
410
+    public function getFileKey($path, $uid) {
411
+        if ($uid === '') {
412
+            $uid = null;
413
+        }
414
+        $publicAccess = is_null($uid);
415
+        $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
416
+
417
+        if (empty($encryptedFileKey)) {
418
+            return '';
419
+        }
420
+
421
+        if ($this->util->isMasterKeyEnabled()) {
422
+            $uid = $this->getMasterKeyId();
423
+            $shareKey = $this->getShareKey($path, $uid);
424
+            if ($publicAccess) {
425
+                $privateKey = $this->getSystemPrivateKey($uid);
426
+                $privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
427
+            } else {
428
+                // when logged in, the master key is already decrypted in the session
429
+                $privateKey = $this->session->getPrivateKey();
430
+            }
431
+        } else if ($publicAccess) {
432
+            // use public share key for public links
433
+            $uid = $this->getPublicShareKeyId();
434
+            $shareKey = $this->getShareKey($path, $uid);
435
+            $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
436
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey);
437
+        } else {
438
+            $shareKey = $this->getShareKey($path, $uid);
439
+            $privateKey = $this->session->getPrivateKey();
440
+        }
441
+
442
+        if ($encryptedFileKey && $shareKey && $privateKey) {
443
+            return $this->crypt->multiKeyDecrypt($encryptedFileKey,
444
+                $shareKey,
445
+                $privateKey);
446
+        }
447
+
448
+        return '';
449
+    }
450
+
451
+    /**
452
+     * Get the current version of a file
453
+     *
454
+     * @param string $path
455
+     * @param View $view
456
+     * @return int
457
+     */
458
+    public function getVersion($path, View $view) {
459
+        $fileInfo = $view->getFileInfo($path);
460
+        if($fileInfo === false) {
461
+            return 0;
462
+        }
463
+        return $fileInfo->getEncryptedVersion();
464
+    }
465
+
466
+    /**
467
+     * Set the current version of a file
468
+     *
469
+     * @param string $path
470
+     * @param int $version
471
+     * @param View $view
472
+     */
473
+    public function setVersion($path, $version, View $view) {
474
+        $fileInfo= $view->getFileInfo($path);
475
+
476
+        if($fileInfo !== false) {
477
+            $cache = $fileInfo->getStorage()->getCache();
478
+            $cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479
+        }
480
+    }
481
+
482
+    /**
483
+     * get the encrypted file key
484
+     *
485
+     * @param string $path
486
+     * @return string
487
+     */
488
+    public function getEncryptedFileKey($path) {
489
+        $encryptedFileKey = $this->keyStorage->getFileKey($path,
490
+            $this->fileKeyId, Encryption::ID);
491
+
492
+        return $encryptedFileKey;
493
+    }
494
+
495
+    /**
496
+     * delete share key
497
+     *
498
+     * @param string $path
499
+     * @param string $keyId
500
+     * @return boolean
501
+     */
502
+    public function deleteShareKey($path, $keyId) {
503
+        return $this->keyStorage->deleteFileKey(
504
+            $path,
505
+            $keyId . '.' . $this->shareKeyId,
506
+            Encryption::ID);
507
+    }
508
+
509
+
510
+    /**
511
+     * @param $path
512
+     * @param $uid
513
+     * @return mixed
514
+     */
515
+    public function getShareKey($path, $uid) {
516
+        $keyId = $uid . '.' . $this->shareKeyId;
517
+        return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518
+    }
519
+
520
+    /**
521
+     * check if user has a private and a public key
522
+     *
523
+     * @param string $userId
524
+     * @return bool
525
+     * @throws PrivateKeyMissingException
526
+     * @throws PublicKeyMissingException
527
+     */
528
+    public function userHasKeys($userId) {
529
+        $privateKey = $publicKey = true;
530
+        $exception = null;
531
+
532
+        try {
533
+            $this->getPrivateKey($userId);
534
+        } catch (PrivateKeyMissingException $e) {
535
+            $privateKey = false;
536
+            $exception = $e;
537
+        }
538
+        try {
539
+            $this->getPublicKey($userId);
540
+        } catch (PublicKeyMissingException $e) {
541
+            $publicKey = false;
542
+            $exception = $e;
543
+        }
544
+
545
+        if ($privateKey && $publicKey) {
546
+            return true;
547
+        } elseif (!$privateKey && !$publicKey) {
548
+            return false;
549
+        } else {
550
+            throw $exception;
551
+        }
552
+    }
553
+
554
+    /**
555
+     * @param $userId
556
+     * @return mixed
557
+     * @throws PublicKeyMissingException
558
+     */
559
+    public function getPublicKey($userId) {
560
+        $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
561
+
562
+        if (strlen($publicKey) !== 0) {
563
+            return $publicKey;
564
+        }
565
+        throw new PublicKeyMissingException($userId);
566
+    }
567
+
568
+    public function getPublicShareKeyId() {
569
+        return $this->publicShareKeyId;
570
+    }
571
+
572
+    /**
573
+     * get public key for public link shares
574
+     *
575
+     * @return string
576
+     */
577
+    public function getPublicShareKey() {
578
+        return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
579
+    }
580
+
581
+    /**
582
+     * @param string $purpose
583
+     * @param string $uid
584
+     */
585
+    public function backupUserKeys($purpose, $uid) {
586
+        $this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
587
+    }
588
+
589
+    /**
590
+     * creat a backup of the users private and public key and then  delete it
591
+     *
592
+     * @param string $uid
593
+     */
594
+    public function deleteUserKeys($uid) {
595
+        $this->deletePublicKey($uid);
596
+        $this->deletePrivateKey($uid);
597
+    }
598
+
599
+    /**
600
+     * @param $uid
601
+     * @return bool
602
+     */
603
+    public function deletePublicKey($uid) {
604
+        return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
605
+    }
606
+
607
+    /**
608
+     * @param string $uid
609
+     * @return bool
610
+     */
611
+    private function deletePrivateKey($uid) {
612
+        return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
613
+    }
614
+
615
+    /**
616
+     * @param string $path
617
+     * @return bool
618
+     */
619
+    public function deleteAllFileKeys($path) {
620
+        return $this->keyStorage->deleteAllFileKeys($path);
621
+    }
622
+
623
+    /**
624
+     * @param array $userIds
625
+     * @return array
626
+     * @throws PublicKeyMissingException
627
+     */
628
+    public function getPublicKeys(array $userIds) {
629
+        $keys = [];
630
+
631
+        foreach ($userIds as $userId) {
632
+            try {
633
+                $keys[$userId] = $this->getPublicKey($userId);
634
+            } catch (PublicKeyMissingException $e) {
635
+                continue;
636
+            }
637
+        }
638
+
639
+        return $keys;
640
+
641
+    }
642
+
643
+    /**
644
+     * @param string $keyId
645
+     * @return string returns openssl key
646
+     */
647
+    public function getSystemPrivateKey($keyId) {
648
+        return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
649
+    }
650
+
651
+    /**
652
+     * @param string $keyId
653
+     * @param string $key
654
+     * @return string returns openssl key
655
+     */
656
+    public function setSystemPrivateKey($keyId, $key) {
657
+        return $this->keyStorage->setSystemUserKey(
658
+            $keyId . '.' . $this->privateKeyId,
659
+            $key,
660
+            Encryption::ID);
661
+    }
662
+
663
+    /**
664
+     * add system keys such as the public share key and the recovery key
665
+     *
666
+     * @param array $accessList
667
+     * @param array $publicKeys
668
+     * @param string $uid
669
+     * @return array
670
+     * @throws PublicKeyMissingException
671
+     */
672
+    public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
673
+        if (!empty($accessList['public'])) {
674
+            $publicShareKey = $this->getPublicShareKey();
675
+            if (empty($publicShareKey)) {
676
+                throw new PublicKeyMissingException($this->getPublicShareKeyId());
677
+            }
678
+            $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
679
+        }
680
+
681
+        if ($this->recoveryKeyExists() &&
682
+            $this->util->isRecoveryEnabledForUser($uid)) {
683
+
684
+            $publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
685
+        }
686
+
687
+        return $publicKeys;
688
+    }
689
+
690
+    /**
691
+     * get master key password
692
+     *
693
+     * @return string
694
+     * @throws \Exception
695
+     */
696
+    public function getMasterKeyPassword() {
697
+        $password = $this->config->getSystemValue('secret');
698
+        if (empty($password)){
699
+            throw new \Exception('Can not get secret from Nextcloud instance');
700
+        }
701
+
702
+        return $password;
703
+    }
704
+
705
+    /**
706
+     * return master key id
707
+     *
708
+     * @return string
709
+     */
710
+    public function getMasterKeyId() {
711
+        return $this->masterKeyId;
712
+    }
713
+
714
+    /**
715
+     * get public master key
716
+     *
717
+     * @return string
718
+     */
719
+    public function getPublicMasterKey() {
720
+        return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
721
+    }
722 722
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127 127
 			'recoveryKeyId');
128 128
 		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
129
+			$this->recoveryKeyId = 'recoveryKey_'.substr(md5(time()), 0, 8);
130 130
 			$this->config->setAppValue('encryption',
131 131
 				'recoveryKeyId',
132 132
 				$this->recoveryKeyId);
@@ -135,14 +135,14 @@  discard block
 block discarded – undo
135 135
 		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136 136
 			'publicShareKeyId');
137 137
 		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
138
+			$this->publicShareKeyId = 'pubShare_'.substr(md5(time()), 0, 8);
139 139
 			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140 140
 		}
141 141
 
142 142
 		$this->masterKeyId = $this->config->getAppValue('encryption',
143 143
 			'masterKeyId');
144 144
 		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
145
+			$this->masterKeyId = 'master_'.substr(md5(time()), 0, 8);
146 146
 			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147 147
 		}
148 148
 
@@ -160,13 +160,13 @@  discard block
 block discarded – undo
160 160
 
161 161
 			// Save public key
162 162
 			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
163
+				$this->publicShareKeyId.'.publicKey', $keyPair['publicKey'],
164 164
 				Encryption::ID);
165 165
 
166 166
 			// Encrypt private key empty passphrase
167 167
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168 168
 			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
169
+			$this->setSystemPrivateKey($this->publicShareKeyId, $header.$encryptedKey);
170 170
 		}
171 171
 	}
172 172
 
@@ -185,13 +185,13 @@  discard block
 block discarded – undo
185 185
 
186 186
 			// Save public key
187 187
 			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
188
+				$this->masterKeyId.'.publicKey', $keyPair['publicKey'],
189 189
 				Encryption::ID);
190 190
 
191 191
 			// Encrypt private key with system password
192 192
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193 193
 			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
194
+			$this->setSystemPrivateKey($this->masterKeyId, $header.$encryptedKey);
195 195
 		}
196 196
 
197 197
 		if (!$this->session->isPrivateKeySet()) {
@@ -218,7 +218,7 @@  discard block
 block discarded – undo
218 218
 	 * @return string
219 219
 	 */
220 220
 	public function getRecoveryKey() {
221
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
221
+		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.publicKey', Encryption::ID);
222 222
 	}
223 223
 
224 224
 	/**
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
 	 * @return bool
236 236
 	 */
237 237
 	public function checkRecoveryPassword($password) {
238
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
238
+		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.privateKey', Encryption::ID);
239 239
 		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240 240
 
241 241
 		if ($decryptedRecoveryKey) {
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
 		$header = $this->crypt->generateHeader();
260 260
 
261 261
 		if ($encryptedKey) {
262
-			$this->setPrivateKey($uid, $header . $encryptedKey);
262
+			$this->setPrivateKey($uid, $header.$encryptedKey);
263 263
 			return true;
264 264
 		}
265 265
 		return false;
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
 		$header = $this->crypt->generateHeader();
282 282
 
283 283
 		if ($encryptedKey) {
284
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
284
+			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header.$encryptedKey);
285 285
 			return true;
286 286
 		}
287 287
 		return false;
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
 	 * @return boolean
342 342
 	 */
343 343
 	public function setShareKey($path, $uid, $key) {
344
-		$keyId = $uid . '.' . $this->shareKeyId;
344
+		$keyId = $uid.'.'.$this->shareKeyId;
345 345
 		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346 346
 	}
347 347
 
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 		$this->session->setStatus(Session::INIT_EXECUTED);
358 358
 
359 359
 		try {
360
-			if($this->util->isMasterKeyEnabled()) {
360
+			if ($this->util->isMasterKeyEnabled()) {
361 361
 				$uid = $this->getMasterKeyId();
362 362
 				$passPhrase = $this->getMasterKeyPassword();
363 363
 				$privateKey = $this->getSystemPrivateKey($uid);
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
 			return false;
372 372
 		} catch (\Exception $e) {
373 373
 			$this->log->warning(
374
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
374
+				'Could not decrypt the private key from user "'.$uid.'"" during login. '.
375 375
 				'Assume password change on the user back-end. Error message: '
376 376
 				. $e->getMessage()
377 377
 			);
@@ -432,7 +432,7 @@  discard block
 block discarded – undo
432 432
 			// use public share key for public links
433 433
 			$uid = $this->getPublicShareKeyId();
434 434
 			$shareKey = $this->getShareKey($path, $uid);
435
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
435
+			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.privateKey', Encryption::ID);
436 436
 			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
437 437
 		} else {
438 438
 			$shareKey = $this->getShareKey($path, $uid);
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
 	 */
458 458
 	public function getVersion($path, View $view) {
459 459
 		$fileInfo = $view->getFileInfo($path);
460
-		if($fileInfo === false) {
460
+		if ($fileInfo === false) {
461 461
 			return 0;
462 462
 		}
463 463
 		return $fileInfo->getEncryptedVersion();
@@ -471,9 +471,9 @@  discard block
 block discarded – undo
471 471
 	 * @param View $view
472 472
 	 */
473 473
 	public function setVersion($path, $version, View $view) {
474
-		$fileInfo= $view->getFileInfo($path);
474
+		$fileInfo = $view->getFileInfo($path);
475 475
 
476
-		if($fileInfo !== false) {
476
+		if ($fileInfo !== false) {
477 477
 			$cache = $fileInfo->getStorage()->getCache();
478 478
 			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479 479
 		}
@@ -502,7 +502,7 @@  discard block
 block discarded – undo
502 502
 	public function deleteShareKey($path, $keyId) {
503 503
 		return $this->keyStorage->deleteFileKey(
504 504
 			$path,
505
-			$keyId . '.' . $this->shareKeyId,
505
+			$keyId.'.'.$this->shareKeyId,
506 506
 			Encryption::ID);
507 507
 	}
508 508
 
@@ -513,7 +513,7 @@  discard block
 block discarded – undo
513 513
 	 * @return mixed
514 514
 	 */
515 515
 	public function getShareKey($path, $uid) {
516
-		$keyId = $uid . '.' . $this->shareKeyId;
516
+		$keyId = $uid.'.'.$this->shareKeyId;
517 517
 		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518 518
 	}
519 519
 
@@ -575,7 +575,7 @@  discard block
 block discarded – undo
575 575
 	 * @return string
576 576
 	 */
577 577
 	public function getPublicShareKey() {
578
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
578
+		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.publicKey', Encryption::ID);
579 579
 	}
580 580
 
581 581
 	/**
@@ -645,7 +645,7 @@  discard block
 block discarded – undo
645 645
 	 * @return string returns openssl key
646 646
 	 */
647 647
 	public function getSystemPrivateKey($keyId) {
648
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
648
+		return $this->keyStorage->getSystemUserKey($keyId.'.'.$this->privateKeyId, Encryption::ID);
649 649
 	}
650 650
 
651 651
 	/**
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
 	 */
656 656
 	public function setSystemPrivateKey($keyId, $key) {
657 657
 		return $this->keyStorage->setSystemUserKey(
658
-			$keyId . '.' . $this->privateKeyId,
658
+			$keyId.'.'.$this->privateKeyId,
659 659
 			$key,
660 660
 			Encryption::ID);
661 661
 	}
@@ -695,7 +695,7 @@  discard block
 block discarded – undo
695 695
 	 */
696 696
 	public function getMasterKeyPassword() {
697 697
 		$password = $this->config->getSystemValue('secret');
698
-		if (empty($password)){
698
+		if (empty($password)) {
699 699
 			throw new \Exception('Can not get secret from Nextcloud instance');
700 700
 		}
701 701
 
@@ -717,6 +717,6 @@  discard block
 block discarded – undo
717 717
 	 * @return string
718 718
 	 */
719 719
 	public function getPublicMasterKey() {
720
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
720
+		return $this->keyStorage->getSystemUserKey($this->masterKeyId.'.publicKey', Encryption::ID);
721 721
 	}
722 722
 }
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 1 patch
Indentation   +974 added lines, -974 removed lines patch added patch discarded remove patch
@@ -62,979 +62,979 @@
 block discarded – undo
62 62
  * @package OC\Settings\Controller
63 63
  */
64 64
 class UsersController extends Controller {
65
-	/** @var IL10N */
66
-	private $l10n;
67
-	/** @var IUserSession */
68
-	private $userSession;
69
-	/** @var bool */
70
-	private $isAdmin;
71
-	/** @var IUserManager */
72
-	private $userManager;
73
-	/** @var IGroupManager */
74
-	private $groupManager;
75
-	/** @var IConfig */
76
-	private $config;
77
-	/** @var ILogger */
78
-	private $log;
79
-	/** @var IMailer */
80
-	private $mailer;
81
-	/** @var bool contains the state of the encryption app */
82
-	private $isEncryptionAppEnabled;
83
-	/** @var bool contains the state of the admin recovery setting */
84
-	private $isRestoreEnabled = false;
85
-	/** @var IAppManager */
86
-	private $appManager;
87
-	/** @var IAvatarManager */
88
-	private $avatarManager;
89
-	/** @var AccountManager */
90
-	private $accountManager;
91
-	/** @var ISecureRandom */
92
-	private $secureRandom;
93
-	/** @var NewUserMailHelper */
94
-	private $newUserMailHelper;
95
-	/** @var ITimeFactory */
96
-	private $timeFactory;
97
-	/** @var ICrypto */
98
-	private $crypto;
99
-	/** @var Manager */
100
-	private $keyManager;
101
-	/** @var IJobList */
102
-	private $jobList;
103
-
104
-	/** @var IUserMountCache */
105
-	private $userMountCache;
106
-
107
-	/** @var IManager */
108
-	private $encryptionManager;
109
-
110
-
111
-	/**
112
-	 * @param string $appName
113
-	 * @param IRequest $request
114
-	 * @param IUserManager $userManager
115
-	 * @param IGroupManager $groupManager
116
-	 * @param IUserSession $userSession
117
-	 * @param IConfig $config
118
-	 * @param bool $isAdmin
119
-	 * @param IL10N $l10n
120
-	 * @param ILogger $log
121
-	 * @param IMailer $mailer
122
-	 * @param IURLGenerator $urlGenerator
123
-	 * @param IAppManager $appManager
124
-	 * @param IAvatarManager $avatarManager
125
-	 * @param AccountManager $accountManager
126
-	 * @param ISecureRandom $secureRandom
127
-	 * @param NewUserMailHelper $newUserMailHelper
128
-	 * @param ITimeFactory $timeFactory
129
-	 * @param ICrypto $crypto
130
-	 * @param Manager $keyManager
131
-	 * @param IJobList $jobList
132
-	 * @param IUserMountCache $userMountCache
133
-	 * @param IManager $encryptionManager
134
-	 */
135
-	public function __construct($appName,
136
-								IRequest $request,
137
-								IUserManager $userManager,
138
-								IGroupManager $groupManager,
139
-								IUserSession $userSession,
140
-								IConfig $config,
141
-								$isAdmin,
142
-								IL10N $l10n,
143
-								ILogger $log,
144
-								IMailer $mailer,
145
-								IURLGenerator $urlGenerator,
146
-								IAppManager $appManager,
147
-								IAvatarManager $avatarManager,
148
-								AccountManager $accountManager,
149
-								ISecureRandom $secureRandom,
150
-								NewUserMailHelper $newUserMailHelper,
151
-								ITimeFactory $timeFactory,
152
-								ICrypto $crypto,
153
-								Manager $keyManager,
154
-								IJobList $jobList,
155
-								IUserMountCache $userMountCache,
156
-								IManager $encryptionManager) {
157
-		parent::__construct($appName, $request);
158
-		$this->userManager = $userManager;
159
-		$this->groupManager = $groupManager;
160
-		$this->userSession = $userSession;
161
-		$this->config = $config;
162
-		$this->isAdmin = $isAdmin;
163
-		$this->l10n = $l10n;
164
-		$this->log = $log;
165
-		$this->mailer = $mailer;
166
-		$this->appManager = $appManager;
167
-		$this->avatarManager = $avatarManager;
168
-		$this->accountManager = $accountManager;
169
-		$this->secureRandom = $secureRandom;
170
-		$this->newUserMailHelper = $newUserMailHelper;
171
-		$this->timeFactory = $timeFactory;
172
-		$this->crypto = $crypto;
173
-		$this->keyManager = $keyManager;
174
-		$this->jobList = $jobList;
175
-		$this->userMountCache = $userMountCache;
176
-		$this->encryptionManager = $encryptionManager;
177
-
178
-		// check for encryption state - TODO see formatUserForIndex
179
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
180
-		if ($this->isEncryptionAppEnabled) {
181
-			// putting this directly in empty is possible in PHP 5.5+
182
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
183
-			$this->isRestoreEnabled = !empty($result);
184
-		}
185
-	}
186
-
187
-	/**
188
-	 * @param IUser $user
189
-	 * @param array $userGroups
190
-	 * @return array
191
-	 */
192
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
193
-
194
-		// TODO: eliminate this encryption specific code below and somehow
195
-		// hook in additional user info from other apps
196
-
197
-		// recovery isn't possible if admin or user has it disabled and encryption
198
-		// is enabled - so we eliminate the else paths in the conditional tree
199
-		// below
200
-		$restorePossible = false;
201
-
202
-		if ($this->isEncryptionAppEnabled) {
203
-			if ($this->isRestoreEnabled) {
204
-				// check for the users recovery setting
205
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
206
-				// method call inside empty is possible with PHP 5.5+
207
-				$recoveryModeEnabled = !empty($recoveryMode);
208
-				if ($recoveryModeEnabled) {
209
-					// user also has recovery mode enabled
210
-					$restorePossible = true;
211
-				}
212
-			} else {
213
-				$modules = $this->encryptionManager->getEncryptionModules();
214
-				$restorePossible = true;
215
-				foreach ($modules as $id => $module) {
216
-					/* @var IEncryptionModule $instance */
217
-					$instance = call_user_func($module['callback']);
218
-					if ($instance->needDetailedAccessList()) {
219
-						$restorePossible = false;
220
-						break;
221
-					}
222
-				}
223
-			}
224
-		} else {
225
-			// recovery is possible if encryption is disabled (plain files are
226
-			// available)
227
-			$restorePossible = true;
228
-		}
229
-
230
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
231
-		foreach ($subAdminGroups as $key => $subAdminGroup) {
232
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
233
-		}
234
-
235
-		$displayName = $user->getEMailAddress();
236
-		if (is_null($displayName)) {
237
-			$displayName = '';
238
-		}
239
-
240
-		$avatarAvailable = false;
241
-		try {
242
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
243
-		} catch (\Exception $e) {
244
-			//No avatar yet
245
-		}
246
-
247
-		return [
248
-			'name' => $user->getUID(),
249
-			'displayname' => $user->getDisplayName(),
250
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
251
-			'subadmin' => $subAdminGroups,
252
-			'quota' => $user->getQuota(),
253
-			'quota_bytes' => Util::computerFileSize($user->getQuota()),
254
-			'storageLocation' => $user->getHome(),
255
-			'lastLogin' => $user->getLastLogin() * 1000,
256
-			'backend' => $user->getBackendClassName(),
257
-			'email' => $displayName,
258
-			'isRestoreDisabled' => !$restorePossible,
259
-			'isAvatarAvailable' => $avatarAvailable,
260
-			'isEnabled' => $user->isEnabled(),
261
-		];
262
-	}
263
-
264
-	/**
265
-	 * @param array $userIDs Array with schema [$uid => $displayName]
266
-	 * @return IUser[]
267
-	 */
268
-	private function getUsersForUID(array $userIDs) {
269
-		$users = [];
270
-		foreach ($userIDs as $uid => $displayName) {
271
-			$users[$uid] = $this->userManager->get($uid);
272
-		}
273
-		return $users;
274
-	}
275
-
276
-	/**
277
-	 * @NoAdminRequired
278
-	 *
279
-	 * @param int $offset
280
-	 * @param int $limit
281
-	 * @param string $gid GID to filter for
282
-	 * @param string $pattern Pattern to search for in the username
283
-	 * @param string $backend Backend to filter for (class-name)
284
-	 * @return DataResponse
285
-	 *
286
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
287
-	 */
288
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
289
-		// Remove backends
290
-		if (!empty($backend)) {
291
-			$activeBackends = $this->userManager->getBackends();
292
-			$this->userManager->clearBackends();
293
-			foreach ($activeBackends as $singleActiveBackend) {
294
-				if ($backend === get_class($singleActiveBackend)) {
295
-					$this->userManager->registerBackend($singleActiveBackend);
296
-					break;
297
-				}
298
-			}
299
-		}
300
-
301
-		$userObjects = [];
302
-		$users = [];
303
-		if ($this->isAdmin) {
304
-			if ($gid !== '' && $gid !== '_disabledUsers') {
305
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
306
-			} else {
307
-				$batch = $this->userManager->search($pattern, $limit, $offset);
308
-			}
309
-
310
-			foreach ($batch as $user) {
311
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
312
-					($gid === '_disabledUsers' && !$user->isEnabled())
313
-				) {
314
-					$userObjects[] = $user;
315
-					$users[] = $this->formatUserForIndex($user);
316
-				}
317
-			}
318
-
319
-		} else {
320
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
321
-			// New class returns IGroup[] so convert back
322
-			$gids = [];
323
-			foreach ($subAdminOfGroups as $group) {
324
-				$gids[] = $group->getGID();
325
-			}
326
-			$subAdminOfGroups = $gids;
327
-
328
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
329
-			if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
330
-				$gid = '';
331
-			}
332
-
333
-			// Batch all groups the user is subadmin of when a group is specified
334
-			$batch = [];
335
-			if ($gid === '') {
336
-				foreach ($subAdminOfGroups as $group) {
337
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
338
-
339
-					foreach ($groupUsers as $uid => $displayName) {
340
-						$batch[$uid] = $displayName;
341
-					}
342
-				}
343
-			} else {
344
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
345
-			}
346
-			$batch = $this->getUsersForUID($batch);
347
-
348
-			foreach ($batch as $user) {
349
-				// Only add the groups, this user is a subadmin of
350
-				$userGroups = array_values(array_intersect(
351
-					$this->groupManager->getUserGroupIds($user),
352
-					$subAdminOfGroups
353
-				));
354
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
355
-					($gid === '_disabledUsers' && !$user->isEnabled())
356
-				) {
357
-					$userObjects[] = $user;
358
-					$users[] = $this->formatUserForIndex($user, $userGroups);
359
-				}
360
-			}
361
-		}
362
-
363
-		$usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
364
-
365
-		foreach ($users as &$userData) {
366
-			$userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
367
-		}
368
-
369
-		return new DataResponse($users);
370
-	}
371
-
372
-	/**
373
-	 * @NoAdminRequired
374
-	 * @PasswordConfirmationRequired
375
-	 *
376
-	 * @param string $username
377
-	 * @param string $password
378
-	 * @param array $groups
379
-	 * @param string $email
380
-	 * @return DataResponse
381
-	 */
382
-	public function create($username, $password, array $groups = [], $email = '') {
383
-		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
384
-			return new DataResponse(
385
-				[
386
-					'message' => (string)$this->l10n->t('Invalid mail address')
387
-				],
388
-				Http::STATUS_UNPROCESSABLE_ENTITY
389
-			);
390
-		}
391
-
392
-		$currentUser = $this->userSession->getUser();
393
-
394
-		if (!$this->isAdmin) {
395
-			if (!empty($groups)) {
396
-				foreach ($groups as $key => $group) {
397
-					$groupObject = $this->groupManager->get($group);
398
-					if ($groupObject === null) {
399
-						unset($groups[$key]);
400
-						continue;
401
-					}
402
-
403
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
404
-						unset($groups[$key]);
405
-					}
406
-				}
407
-			}
408
-
409
-			if (empty($groups)) {
410
-				return new DataResponse(
411
-					[
412
-						'message' => $this->l10n->t('No valid group selected'),
413
-					],
414
-					Http::STATUS_FORBIDDEN
415
-				);
416
-			}
417
-		}
418
-
419
-		if ($this->userManager->userExists($username)) {
420
-			return new DataResponse(
421
-				[
422
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
423
-				],
424
-				Http::STATUS_CONFLICT
425
-			);
426
-		}
427
-
428
-		$generatePasswordResetToken = false;
429
-		if ($password === '') {
430
-			if ($email === '') {
431
-				return new DataResponse(
432
-					[
433
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
434
-					],
435
-					Http::STATUS_UNPROCESSABLE_ENTITY
436
-				);
437
-			}
438
-
439
-			$password = $this->secureRandom->generate(32);
440
-			$generatePasswordResetToken = true;
441
-		}
442
-
443
-		try {
444
-			$user = $this->userManager->createUser($username, $password);
445
-		} catch (\Exception $exception) {
446
-			$message = $exception->getMessage();
447
-			if (!$message) {
448
-				$message = $this->l10n->t('Unable to create user.');
449
-			}
450
-			return new DataResponse(
451
-				[
452
-					'message' => (string)$message,
453
-				],
454
-				Http::STATUS_FORBIDDEN
455
-			);
456
-		}
457
-
458
-		if ($user instanceof IUser) {
459
-			if ($groups !== null) {
460
-				foreach ($groups as $groupName) {
461
-					$group = $this->groupManager->get($groupName);
462
-
463
-					if (empty($group)) {
464
-						$group = $this->groupManager->createGroup($groupName);
465
-					}
466
-					$group->addUser($user);
467
-				}
468
-			}
469
-			/**
470
-			 * Send new user mail only if a mail is set
471
-			 */
472
-			if ($email !== '') {
473
-				$user->setEMailAddress($email);
474
-				try {
475
-					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
476
-					$this->newUserMailHelper->sendMail($user, $emailTemplate);
477
-				} catch (\Exception $e) {
478
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
479
-				}
480
-			}
481
-			// fetch users groups
482
-			$userGroups = $this->groupManager->getUserGroupIds($user);
483
-
484
-			return new DataResponse(
485
-				$this->formatUserForIndex($user, $userGroups),
486
-				Http::STATUS_CREATED
487
-			);
488
-		}
489
-
490
-		return new DataResponse(
491
-			[
492
-				'message' => (string)$this->l10n->t('Unable to create user.')
493
-			],
494
-			Http::STATUS_FORBIDDEN
495
-		);
496
-
497
-	}
498
-
499
-	/**
500
-	 * @NoAdminRequired
501
-	 * @PasswordConfirmationRequired
502
-	 *
503
-	 * @param string $id
504
-	 * @return DataResponse
505
-	 */
506
-	public function destroy($id) {
507
-		$userId = $this->userSession->getUser()->getUID();
508
-		$user = $this->userManager->get($id);
509
-
510
-		if ($userId === $id) {
511
-			return new DataResponse(
512
-				[
513
-					'status' => 'error',
514
-					'data' => [
515
-						'message' => (string)$this->l10n->t('Unable to delete user.')
516
-					]
517
-				],
518
-				Http::STATUS_FORBIDDEN
519
-			);
520
-		}
521
-
522
-		if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
523
-			return new DataResponse(
524
-				[
525
-					'status' => 'error',
526
-					'data' => [
527
-						'message' => (string)$this->l10n->t('Authentication error')
528
-					]
529
-				],
530
-				Http::STATUS_FORBIDDEN
531
-			);
532
-		}
533
-
534
-		if ($user) {
535
-			if ($user->delete()) {
536
-				return new DataResponse(
537
-					[
538
-						'status' => 'success',
539
-						'data' => [
540
-							'username' => $id
541
-						]
542
-					],
543
-					Http::STATUS_NO_CONTENT
544
-				);
545
-			}
546
-		}
547
-
548
-		return new DataResponse(
549
-			[
550
-				'status' => 'error',
551
-				'data' => [
552
-					'message' => (string)$this->l10n->t('Unable to delete user.')
553
-				]
554
-			],
555
-			Http::STATUS_FORBIDDEN
556
-		);
557
-	}
558
-
559
-	/**
560
-	 * @NoAdminRequired
561
-	 *
562
-	 * @param string $id
563
-	 * @param int $enabled
564
-	 * @return DataResponse
565
-	 */
566
-	public function setEnabled($id, $enabled) {
567
-		$enabled = (bool)$enabled;
568
-		if ($enabled) {
569
-			$errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
570
-		} else {
571
-			$errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
572
-		}
573
-
574
-		$userId = $this->userSession->getUser()->getUID();
575
-		$user = $this->userManager->get($id);
576
-
577
-		if ($userId === $id) {
578
-			return new DataResponse(
579
-				[
580
-					'status' => 'error',
581
-					'data' => [
582
-						'message' => $errorMsgGeneral
583
-					]
584
-				], Http::STATUS_FORBIDDEN
585
-			);
586
-		}
587
-
588
-		if ($user) {
589
-			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
590
-				return new DataResponse(
591
-					[
592
-						'status' => 'error',
593
-						'data' => [
594
-							'message' => (string)$this->l10n->t('Authentication error')
595
-						]
596
-					],
597
-					Http::STATUS_FORBIDDEN
598
-				);
599
-			}
600
-
601
-			$user->setEnabled($enabled);
602
-			return new DataResponse(
603
-				[
604
-					'status' => 'success',
605
-					'data' => [
606
-						'username' => $id,
607
-						'enabled' => $enabled
608
-					]
609
-				]
610
-			);
611
-		} else {
612
-			return new DataResponse(
613
-				[
614
-					'status' => 'error',
615
-					'data' => [
616
-						'message' => $errorMsgGeneral
617
-					]
618
-				],
619
-				Http::STATUS_FORBIDDEN
620
-			);
621
-		}
622
-
623
-	}
624
-
625
-	/**
626
-	 * Set the mail address of a user
627
-	 *
628
-	 * @NoAdminRequired
629
-	 * @NoSubadminRequired
630
-	 * @PasswordConfirmationRequired
631
-	 *
632
-	 * @param string $account
633
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
634
-	 * @return DataResponse
635
-	 */
636
-	public function getVerificationCode($account, $onlyVerificationCode) {
637
-
638
-		$user = $this->userSession->getUser();
639
-
640
-		if ($user === null) {
641
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
642
-		}
643
-
644
-		$accountData = $this->accountManager->getUser($user);
645
-		$cloudId = $user->getCloudId();
646
-		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
647
-		$signature = $this->signMessage($user, $message);
648
-
649
-		$code = $message . ' ' . $signature;
650
-		$codeMd5 = $message . ' ' . md5($signature);
651
-
652
-		switch ($account) {
653
-			case 'verify-twitter':
654
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
655
-				$msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
656
-				$code = $codeMd5;
657
-				$type = AccountManager::PROPERTY_TWITTER;
658
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
659
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
660
-				break;
661
-			case 'verify-website':
662
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
663
-				$msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
664
-				$type = AccountManager::PROPERTY_WEBSITE;
665
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
666
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
667
-				break;
668
-			default:
669
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
670
-		}
671
-
672
-		if ($onlyVerificationCode === false) {
673
-			$this->accountManager->updateUser($user, $accountData);
674
-
675
-			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
676
-				[
677
-					'verificationCode' => $code,
678
-					'data' => $data,
679
-					'type' => $type,
680
-					'uid' => $user->getUID(),
681
-					'try' => 0,
682
-					'lastRun' => $this->getCurrentTime()
683
-				]
684
-			);
685
-		}
686
-
687
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
688
-	}
689
-
690
-	/**
691
-	 * get current timestamp
692
-	 *
693
-	 * @return int
694
-	 */
695
-	protected function getCurrentTime() {
696
-		return time();
697
-	}
698
-
699
-	/**
700
-	 * sign message with users private key
701
-	 *
702
-	 * @param IUser $user
703
-	 * @param string $message
704
-	 *
705
-	 * @return string base64 encoded signature
706
-	 */
707
-	protected function signMessage(IUser $user, $message) {
708
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
709
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
710
-		$signatureBase64 = base64_encode($signature);
711
-
712
-		return $signatureBase64;
713
-	}
714
-
715
-	/**
716
-	 * @NoAdminRequired
717
-	 * @NoSubadminRequired
718
-	 * @PasswordConfirmationRequired
719
-	 *
720
-	 * @param string $avatarScope
721
-	 * @param string $displayname
722
-	 * @param string $displaynameScope
723
-	 * @param string $phone
724
-	 * @param string $phoneScope
725
-	 * @param string $email
726
-	 * @param string $emailScope
727
-	 * @param string $website
728
-	 * @param string $websiteScope
729
-	 * @param string $address
730
-	 * @param string $addressScope
731
-	 * @param string $twitter
732
-	 * @param string $twitterScope
733
-	 * @return DataResponse
734
-	 */
735
-	public function setUserSettings($avatarScope,
736
-									$displayname,
737
-									$displaynameScope,
738
-									$phone,
739
-									$phoneScope,
740
-									$email,
741
-									$emailScope,
742
-									$website,
743
-									$websiteScope,
744
-									$address,
745
-									$addressScope,
746
-									$twitter,
747
-									$twitterScope
748
-	) {
749
-
750
-		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
751
-			return new DataResponse(
752
-				[
753
-					'status' => 'error',
754
-					'data' => [
755
-						'message' => (string)$this->l10n->t('Invalid mail address')
756
-					]
757
-				],
758
-				Http::STATUS_UNPROCESSABLE_ENTITY
759
-			);
760
-		}
761
-
762
-		$user = $this->userSession->getUser();
763
-
764
-		$data = $this->accountManager->getUser($user);
765
-
766
-		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
767
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
768
-			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
769
-			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
770
-		}
771
-
772
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
773
-			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
774
-			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
775
-			if ($shareProvider->isLookupServerUploadEnabled()) {
776
-				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
777
-				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
778
-				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
779
-				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
780
-			}
781
-		}
782
-
783
-		try {
784
-			$this->saveUserSettings($user, $data);
785
-			return new DataResponse(
786
-				[
787
-					'status' => 'success',
788
-					'data' => [
789
-						'userId' => $user->getUID(),
790
-						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
791
-						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
792
-						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
793
-						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
794
-						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
795
-						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
796
-						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
797
-						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
798
-						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
799
-						'message' => (string)$this->l10n->t('Settings saved')
800
-					]
801
-				],
802
-				Http::STATUS_OK
803
-			);
804
-		} catch (ForbiddenException $e) {
805
-			return new DataResponse([
806
-				'status' => 'error',
807
-				'data' => [
808
-					'message' => $e->getMessage()
809
-				],
810
-			]);
811
-		}
812
-
813
-	}
814
-
815
-
816
-	/**
817
-	 * update account manager with new user data
818
-	 *
819
-	 * @param IUser $user
820
-	 * @param array $data
821
-	 * @throws ForbiddenException
822
-	 */
823
-	protected function saveUserSettings(IUser $user, $data) {
824
-
825
-		// keep the user back-end up-to-date with the latest display name and email
826
-		// address
827
-		$oldDisplayName = $user->getDisplayName();
828
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
829
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
830
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
831
-		) {
832
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
833
-			if ($result === false) {
834
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
835
-			}
836
-		}
837
-
838
-		$oldEmailAddress = $user->getEMailAddress();
839
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
840
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
841
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
842
-		) {
843
-			// this is the only permission a backend provides and is also used
844
-			// for the permission of setting a email address
845
-			if (!$user->canChangeDisplayName()) {
846
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
847
-			}
848
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
849
-		}
850
-
851
-		$this->accountManager->updateUser($user, $data);
852
-	}
853
-
854
-	/**
855
-	 * Count all unique users visible for the current admin/subadmin.
856
-	 *
857
-	 * @NoAdminRequired
858
-	 *
859
-	 * @return DataResponse
860
-	 */
861
-	public function stats() {
862
-		$userCount = 0;
863
-		if ($this->isAdmin) {
864
-			$countByBackend = $this->userManager->countUsers();
865
-
866
-			if (!empty($countByBackend)) {
867
-				foreach ($countByBackend as $count) {
868
-					$userCount += $count;
869
-				}
870
-			}
871
-		} else {
872
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
873
-
874
-			$uniqueUsers = [];
875
-			foreach ($groups as $group) {
876
-				foreach ($group->getUsers() as $uid => $displayName) {
877
-					$uniqueUsers[$uid] = true;
878
-				}
879
-			}
880
-
881
-			$userCount = count($uniqueUsers);
882
-		}
883
-
884
-		return new DataResponse(
885
-			[
886
-				'totalUsers' => $userCount
887
-			]
888
-		);
889
-	}
890
-
891
-
892
-	/**
893
-	 * Set the displayName of a user
894
-	 *
895
-	 * @NoAdminRequired
896
-	 * @NoSubadminRequired
897
-	 * @PasswordConfirmationRequired
898
-	 * @todo merge into saveUserSettings
899
-	 *
900
-	 * @param string $username
901
-	 * @param string $displayName
902
-	 * @return DataResponse
903
-	 */
904
-	public function setDisplayName($username, $displayName) {
905
-		$currentUser = $this->userSession->getUser();
906
-		$user = $this->userManager->get($username);
907
-
908
-		if ($user === null ||
909
-			!$user->canChangeDisplayName() ||
910
-			(
911
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
912
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
913
-				$currentUser->getUID() !== $username
914
-
915
-			)
916
-		) {
917
-			return new DataResponse([
918
-				'status' => 'error',
919
-				'data' => [
920
-					'message' => $this->l10n->t('Authentication error'),
921
-				],
922
-			]);
923
-		}
924
-
925
-		$userData = $this->accountManager->getUser($user);
926
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
927
-
928
-
929
-		try {
930
-			$this->saveUserSettings($user, $userData);
931
-			return new DataResponse([
932
-				'status' => 'success',
933
-				'data' => [
934
-					'message' => $this->l10n->t('Your full name has been changed.'),
935
-					'username' => $username,
936
-					'displayName' => $displayName,
937
-				],
938
-			]);
939
-		} catch (ForbiddenException $e) {
940
-			return new DataResponse([
941
-				'status' => 'error',
942
-				'data' => [
943
-					'message' => $e->getMessage(),
944
-					'displayName' => $user->getDisplayName(),
945
-				],
946
-			]);
947
-		}
948
-	}
949
-
950
-	/**
951
-	 * Set the mail address of a user
952
-	 *
953
-	 * @NoAdminRequired
954
-	 * @NoSubadminRequired
955
-	 * @PasswordConfirmationRequired
956
-	 *
957
-	 * @param string $id
958
-	 * @param string $mailAddress
959
-	 * @return DataResponse
960
-	 */
961
-	public function setEMailAddress($id, $mailAddress) {
962
-		$user = $this->userManager->get($id);
963
-		if (!$this->isAdmin
964
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
965
-		) {
966
-			return new DataResponse(
967
-				[
968
-					'status' => 'error',
969
-					'data' => [
970
-						'message' => (string)$this->l10n->t('Forbidden')
971
-					]
972
-				],
973
-				Http::STATUS_FORBIDDEN
974
-			);
975
-		}
976
-
977
-		if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
978
-			return new DataResponse(
979
-				[
980
-					'status' => 'error',
981
-					'data' => [
982
-						'message' => (string)$this->l10n->t('Invalid mail address')
983
-					]
984
-				],
985
-				Http::STATUS_UNPROCESSABLE_ENTITY
986
-			);
987
-		}
988
-
989
-		if (!$user) {
990
-			return new DataResponse(
991
-				[
992
-					'status' => 'error',
993
-					'data' => [
994
-						'message' => (string)$this->l10n->t('Invalid user')
995
-					]
996
-				],
997
-				Http::STATUS_UNPROCESSABLE_ENTITY
998
-			);
999
-		}
1000
-		// this is the only permission a backend provides and is also used
1001
-		// for the permission of setting a email address
1002
-		if (!$user->canChangeDisplayName()) {
1003
-			return new DataResponse(
1004
-				[
1005
-					'status' => 'error',
1006
-					'data' => [
1007
-						'message' => (string)$this->l10n->t('Unable to change mail address')
1008
-					]
1009
-				],
1010
-				Http::STATUS_FORBIDDEN
1011
-			);
1012
-		}
1013
-
1014
-		$userData = $this->accountManager->getUser($user);
1015
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
1016
-
1017
-		try {
1018
-			$this->saveUserSettings($user, $userData);
1019
-			return new DataResponse(
1020
-				[
1021
-					'status' => 'success',
1022
-					'data' => [
1023
-						'username' => $id,
1024
-						'mailAddress' => $mailAddress,
1025
-						'message' => (string)$this->l10n->t('Email saved')
1026
-					]
1027
-				],
1028
-				Http::STATUS_OK
1029
-			);
1030
-		} catch (ForbiddenException $e) {
1031
-			return new DataResponse([
1032
-				'status' => 'error',
1033
-				'data' => [
1034
-					'message' => $e->getMessage()
1035
-				],
1036
-			]);
1037
-		}
1038
-	}
65
+    /** @var IL10N */
66
+    private $l10n;
67
+    /** @var IUserSession */
68
+    private $userSession;
69
+    /** @var bool */
70
+    private $isAdmin;
71
+    /** @var IUserManager */
72
+    private $userManager;
73
+    /** @var IGroupManager */
74
+    private $groupManager;
75
+    /** @var IConfig */
76
+    private $config;
77
+    /** @var ILogger */
78
+    private $log;
79
+    /** @var IMailer */
80
+    private $mailer;
81
+    /** @var bool contains the state of the encryption app */
82
+    private $isEncryptionAppEnabled;
83
+    /** @var bool contains the state of the admin recovery setting */
84
+    private $isRestoreEnabled = false;
85
+    /** @var IAppManager */
86
+    private $appManager;
87
+    /** @var IAvatarManager */
88
+    private $avatarManager;
89
+    /** @var AccountManager */
90
+    private $accountManager;
91
+    /** @var ISecureRandom */
92
+    private $secureRandom;
93
+    /** @var NewUserMailHelper */
94
+    private $newUserMailHelper;
95
+    /** @var ITimeFactory */
96
+    private $timeFactory;
97
+    /** @var ICrypto */
98
+    private $crypto;
99
+    /** @var Manager */
100
+    private $keyManager;
101
+    /** @var IJobList */
102
+    private $jobList;
103
+
104
+    /** @var IUserMountCache */
105
+    private $userMountCache;
106
+
107
+    /** @var IManager */
108
+    private $encryptionManager;
109
+
110
+
111
+    /**
112
+     * @param string $appName
113
+     * @param IRequest $request
114
+     * @param IUserManager $userManager
115
+     * @param IGroupManager $groupManager
116
+     * @param IUserSession $userSession
117
+     * @param IConfig $config
118
+     * @param bool $isAdmin
119
+     * @param IL10N $l10n
120
+     * @param ILogger $log
121
+     * @param IMailer $mailer
122
+     * @param IURLGenerator $urlGenerator
123
+     * @param IAppManager $appManager
124
+     * @param IAvatarManager $avatarManager
125
+     * @param AccountManager $accountManager
126
+     * @param ISecureRandom $secureRandom
127
+     * @param NewUserMailHelper $newUserMailHelper
128
+     * @param ITimeFactory $timeFactory
129
+     * @param ICrypto $crypto
130
+     * @param Manager $keyManager
131
+     * @param IJobList $jobList
132
+     * @param IUserMountCache $userMountCache
133
+     * @param IManager $encryptionManager
134
+     */
135
+    public function __construct($appName,
136
+                                IRequest $request,
137
+                                IUserManager $userManager,
138
+                                IGroupManager $groupManager,
139
+                                IUserSession $userSession,
140
+                                IConfig $config,
141
+                                $isAdmin,
142
+                                IL10N $l10n,
143
+                                ILogger $log,
144
+                                IMailer $mailer,
145
+                                IURLGenerator $urlGenerator,
146
+                                IAppManager $appManager,
147
+                                IAvatarManager $avatarManager,
148
+                                AccountManager $accountManager,
149
+                                ISecureRandom $secureRandom,
150
+                                NewUserMailHelper $newUserMailHelper,
151
+                                ITimeFactory $timeFactory,
152
+                                ICrypto $crypto,
153
+                                Manager $keyManager,
154
+                                IJobList $jobList,
155
+                                IUserMountCache $userMountCache,
156
+                                IManager $encryptionManager) {
157
+        parent::__construct($appName, $request);
158
+        $this->userManager = $userManager;
159
+        $this->groupManager = $groupManager;
160
+        $this->userSession = $userSession;
161
+        $this->config = $config;
162
+        $this->isAdmin = $isAdmin;
163
+        $this->l10n = $l10n;
164
+        $this->log = $log;
165
+        $this->mailer = $mailer;
166
+        $this->appManager = $appManager;
167
+        $this->avatarManager = $avatarManager;
168
+        $this->accountManager = $accountManager;
169
+        $this->secureRandom = $secureRandom;
170
+        $this->newUserMailHelper = $newUserMailHelper;
171
+        $this->timeFactory = $timeFactory;
172
+        $this->crypto = $crypto;
173
+        $this->keyManager = $keyManager;
174
+        $this->jobList = $jobList;
175
+        $this->userMountCache = $userMountCache;
176
+        $this->encryptionManager = $encryptionManager;
177
+
178
+        // check for encryption state - TODO see formatUserForIndex
179
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
180
+        if ($this->isEncryptionAppEnabled) {
181
+            // putting this directly in empty is possible in PHP 5.5+
182
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
183
+            $this->isRestoreEnabled = !empty($result);
184
+        }
185
+    }
186
+
187
+    /**
188
+     * @param IUser $user
189
+     * @param array $userGroups
190
+     * @return array
191
+     */
192
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
193
+
194
+        // TODO: eliminate this encryption specific code below and somehow
195
+        // hook in additional user info from other apps
196
+
197
+        // recovery isn't possible if admin or user has it disabled and encryption
198
+        // is enabled - so we eliminate the else paths in the conditional tree
199
+        // below
200
+        $restorePossible = false;
201
+
202
+        if ($this->isEncryptionAppEnabled) {
203
+            if ($this->isRestoreEnabled) {
204
+                // check for the users recovery setting
205
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
206
+                // method call inside empty is possible with PHP 5.5+
207
+                $recoveryModeEnabled = !empty($recoveryMode);
208
+                if ($recoveryModeEnabled) {
209
+                    // user also has recovery mode enabled
210
+                    $restorePossible = true;
211
+                }
212
+            } else {
213
+                $modules = $this->encryptionManager->getEncryptionModules();
214
+                $restorePossible = true;
215
+                foreach ($modules as $id => $module) {
216
+                    /* @var IEncryptionModule $instance */
217
+                    $instance = call_user_func($module['callback']);
218
+                    if ($instance->needDetailedAccessList()) {
219
+                        $restorePossible = false;
220
+                        break;
221
+                    }
222
+                }
223
+            }
224
+        } else {
225
+            // recovery is possible if encryption is disabled (plain files are
226
+            // available)
227
+            $restorePossible = true;
228
+        }
229
+
230
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
231
+        foreach ($subAdminGroups as $key => $subAdminGroup) {
232
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
233
+        }
234
+
235
+        $displayName = $user->getEMailAddress();
236
+        if (is_null($displayName)) {
237
+            $displayName = '';
238
+        }
239
+
240
+        $avatarAvailable = false;
241
+        try {
242
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
243
+        } catch (\Exception $e) {
244
+            //No avatar yet
245
+        }
246
+
247
+        return [
248
+            'name' => $user->getUID(),
249
+            'displayname' => $user->getDisplayName(),
250
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
251
+            'subadmin' => $subAdminGroups,
252
+            'quota' => $user->getQuota(),
253
+            'quota_bytes' => Util::computerFileSize($user->getQuota()),
254
+            'storageLocation' => $user->getHome(),
255
+            'lastLogin' => $user->getLastLogin() * 1000,
256
+            'backend' => $user->getBackendClassName(),
257
+            'email' => $displayName,
258
+            'isRestoreDisabled' => !$restorePossible,
259
+            'isAvatarAvailable' => $avatarAvailable,
260
+            'isEnabled' => $user->isEnabled(),
261
+        ];
262
+    }
263
+
264
+    /**
265
+     * @param array $userIDs Array with schema [$uid => $displayName]
266
+     * @return IUser[]
267
+     */
268
+    private function getUsersForUID(array $userIDs) {
269
+        $users = [];
270
+        foreach ($userIDs as $uid => $displayName) {
271
+            $users[$uid] = $this->userManager->get($uid);
272
+        }
273
+        return $users;
274
+    }
275
+
276
+    /**
277
+     * @NoAdminRequired
278
+     *
279
+     * @param int $offset
280
+     * @param int $limit
281
+     * @param string $gid GID to filter for
282
+     * @param string $pattern Pattern to search for in the username
283
+     * @param string $backend Backend to filter for (class-name)
284
+     * @return DataResponse
285
+     *
286
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
287
+     */
288
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
289
+        // Remove backends
290
+        if (!empty($backend)) {
291
+            $activeBackends = $this->userManager->getBackends();
292
+            $this->userManager->clearBackends();
293
+            foreach ($activeBackends as $singleActiveBackend) {
294
+                if ($backend === get_class($singleActiveBackend)) {
295
+                    $this->userManager->registerBackend($singleActiveBackend);
296
+                    break;
297
+                }
298
+            }
299
+        }
300
+
301
+        $userObjects = [];
302
+        $users = [];
303
+        if ($this->isAdmin) {
304
+            if ($gid !== '' && $gid !== '_disabledUsers') {
305
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
306
+            } else {
307
+                $batch = $this->userManager->search($pattern, $limit, $offset);
308
+            }
309
+
310
+            foreach ($batch as $user) {
311
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
312
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
313
+                ) {
314
+                    $userObjects[] = $user;
315
+                    $users[] = $this->formatUserForIndex($user);
316
+                }
317
+            }
318
+
319
+        } else {
320
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
321
+            // New class returns IGroup[] so convert back
322
+            $gids = [];
323
+            foreach ($subAdminOfGroups as $group) {
324
+                $gids[] = $group->getGID();
325
+            }
326
+            $subAdminOfGroups = $gids;
327
+
328
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
329
+            if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
330
+                $gid = '';
331
+            }
332
+
333
+            // Batch all groups the user is subadmin of when a group is specified
334
+            $batch = [];
335
+            if ($gid === '') {
336
+                foreach ($subAdminOfGroups as $group) {
337
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
338
+
339
+                    foreach ($groupUsers as $uid => $displayName) {
340
+                        $batch[$uid] = $displayName;
341
+                    }
342
+                }
343
+            } else {
344
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
345
+            }
346
+            $batch = $this->getUsersForUID($batch);
347
+
348
+            foreach ($batch as $user) {
349
+                // Only add the groups, this user is a subadmin of
350
+                $userGroups = array_values(array_intersect(
351
+                    $this->groupManager->getUserGroupIds($user),
352
+                    $subAdminOfGroups
353
+                ));
354
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
355
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
356
+                ) {
357
+                    $userObjects[] = $user;
358
+                    $users[] = $this->formatUserForIndex($user, $userGroups);
359
+                }
360
+            }
361
+        }
362
+
363
+        $usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
364
+
365
+        foreach ($users as &$userData) {
366
+            $userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
367
+        }
368
+
369
+        return new DataResponse($users);
370
+    }
371
+
372
+    /**
373
+     * @NoAdminRequired
374
+     * @PasswordConfirmationRequired
375
+     *
376
+     * @param string $username
377
+     * @param string $password
378
+     * @param array $groups
379
+     * @param string $email
380
+     * @return DataResponse
381
+     */
382
+    public function create($username, $password, array $groups = [], $email = '') {
383
+        if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
384
+            return new DataResponse(
385
+                [
386
+                    'message' => (string)$this->l10n->t('Invalid mail address')
387
+                ],
388
+                Http::STATUS_UNPROCESSABLE_ENTITY
389
+            );
390
+        }
391
+
392
+        $currentUser = $this->userSession->getUser();
393
+
394
+        if (!$this->isAdmin) {
395
+            if (!empty($groups)) {
396
+                foreach ($groups as $key => $group) {
397
+                    $groupObject = $this->groupManager->get($group);
398
+                    if ($groupObject === null) {
399
+                        unset($groups[$key]);
400
+                        continue;
401
+                    }
402
+
403
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
404
+                        unset($groups[$key]);
405
+                    }
406
+                }
407
+            }
408
+
409
+            if (empty($groups)) {
410
+                return new DataResponse(
411
+                    [
412
+                        'message' => $this->l10n->t('No valid group selected'),
413
+                    ],
414
+                    Http::STATUS_FORBIDDEN
415
+                );
416
+            }
417
+        }
418
+
419
+        if ($this->userManager->userExists($username)) {
420
+            return new DataResponse(
421
+                [
422
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
423
+                ],
424
+                Http::STATUS_CONFLICT
425
+            );
426
+        }
427
+
428
+        $generatePasswordResetToken = false;
429
+        if ($password === '') {
430
+            if ($email === '') {
431
+                return new DataResponse(
432
+                    [
433
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
434
+                    ],
435
+                    Http::STATUS_UNPROCESSABLE_ENTITY
436
+                );
437
+            }
438
+
439
+            $password = $this->secureRandom->generate(32);
440
+            $generatePasswordResetToken = true;
441
+        }
442
+
443
+        try {
444
+            $user = $this->userManager->createUser($username, $password);
445
+        } catch (\Exception $exception) {
446
+            $message = $exception->getMessage();
447
+            if (!$message) {
448
+                $message = $this->l10n->t('Unable to create user.');
449
+            }
450
+            return new DataResponse(
451
+                [
452
+                    'message' => (string)$message,
453
+                ],
454
+                Http::STATUS_FORBIDDEN
455
+            );
456
+        }
457
+
458
+        if ($user instanceof IUser) {
459
+            if ($groups !== null) {
460
+                foreach ($groups as $groupName) {
461
+                    $group = $this->groupManager->get($groupName);
462
+
463
+                    if (empty($group)) {
464
+                        $group = $this->groupManager->createGroup($groupName);
465
+                    }
466
+                    $group->addUser($user);
467
+                }
468
+            }
469
+            /**
470
+             * Send new user mail only if a mail is set
471
+             */
472
+            if ($email !== '') {
473
+                $user->setEMailAddress($email);
474
+                try {
475
+                    $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
476
+                    $this->newUserMailHelper->sendMail($user, $emailTemplate);
477
+                } catch (\Exception $e) {
478
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
479
+                }
480
+            }
481
+            // fetch users groups
482
+            $userGroups = $this->groupManager->getUserGroupIds($user);
483
+
484
+            return new DataResponse(
485
+                $this->formatUserForIndex($user, $userGroups),
486
+                Http::STATUS_CREATED
487
+            );
488
+        }
489
+
490
+        return new DataResponse(
491
+            [
492
+                'message' => (string)$this->l10n->t('Unable to create user.')
493
+            ],
494
+            Http::STATUS_FORBIDDEN
495
+        );
496
+
497
+    }
498
+
499
+    /**
500
+     * @NoAdminRequired
501
+     * @PasswordConfirmationRequired
502
+     *
503
+     * @param string $id
504
+     * @return DataResponse
505
+     */
506
+    public function destroy($id) {
507
+        $userId = $this->userSession->getUser()->getUID();
508
+        $user = $this->userManager->get($id);
509
+
510
+        if ($userId === $id) {
511
+            return new DataResponse(
512
+                [
513
+                    'status' => 'error',
514
+                    'data' => [
515
+                        'message' => (string)$this->l10n->t('Unable to delete user.')
516
+                    ]
517
+                ],
518
+                Http::STATUS_FORBIDDEN
519
+            );
520
+        }
521
+
522
+        if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
523
+            return new DataResponse(
524
+                [
525
+                    'status' => 'error',
526
+                    'data' => [
527
+                        'message' => (string)$this->l10n->t('Authentication error')
528
+                    ]
529
+                ],
530
+                Http::STATUS_FORBIDDEN
531
+            );
532
+        }
533
+
534
+        if ($user) {
535
+            if ($user->delete()) {
536
+                return new DataResponse(
537
+                    [
538
+                        'status' => 'success',
539
+                        'data' => [
540
+                            'username' => $id
541
+                        ]
542
+                    ],
543
+                    Http::STATUS_NO_CONTENT
544
+                );
545
+            }
546
+        }
547
+
548
+        return new DataResponse(
549
+            [
550
+                'status' => 'error',
551
+                'data' => [
552
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
553
+                ]
554
+            ],
555
+            Http::STATUS_FORBIDDEN
556
+        );
557
+    }
558
+
559
+    /**
560
+     * @NoAdminRequired
561
+     *
562
+     * @param string $id
563
+     * @param int $enabled
564
+     * @return DataResponse
565
+     */
566
+    public function setEnabled($id, $enabled) {
567
+        $enabled = (bool)$enabled;
568
+        if ($enabled) {
569
+            $errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
570
+        } else {
571
+            $errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
572
+        }
573
+
574
+        $userId = $this->userSession->getUser()->getUID();
575
+        $user = $this->userManager->get($id);
576
+
577
+        if ($userId === $id) {
578
+            return new DataResponse(
579
+                [
580
+                    'status' => 'error',
581
+                    'data' => [
582
+                        'message' => $errorMsgGeneral
583
+                    ]
584
+                ], Http::STATUS_FORBIDDEN
585
+            );
586
+        }
587
+
588
+        if ($user) {
589
+            if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
590
+                return new DataResponse(
591
+                    [
592
+                        'status' => 'error',
593
+                        'data' => [
594
+                            'message' => (string)$this->l10n->t('Authentication error')
595
+                        ]
596
+                    ],
597
+                    Http::STATUS_FORBIDDEN
598
+                );
599
+            }
600
+
601
+            $user->setEnabled($enabled);
602
+            return new DataResponse(
603
+                [
604
+                    'status' => 'success',
605
+                    'data' => [
606
+                        'username' => $id,
607
+                        'enabled' => $enabled
608
+                    ]
609
+                ]
610
+            );
611
+        } else {
612
+            return new DataResponse(
613
+                [
614
+                    'status' => 'error',
615
+                    'data' => [
616
+                        'message' => $errorMsgGeneral
617
+                    ]
618
+                ],
619
+                Http::STATUS_FORBIDDEN
620
+            );
621
+        }
622
+
623
+    }
624
+
625
+    /**
626
+     * Set the mail address of a user
627
+     *
628
+     * @NoAdminRequired
629
+     * @NoSubadminRequired
630
+     * @PasswordConfirmationRequired
631
+     *
632
+     * @param string $account
633
+     * @param bool $onlyVerificationCode only return verification code without updating the data
634
+     * @return DataResponse
635
+     */
636
+    public function getVerificationCode($account, $onlyVerificationCode) {
637
+
638
+        $user = $this->userSession->getUser();
639
+
640
+        if ($user === null) {
641
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
642
+        }
643
+
644
+        $accountData = $this->accountManager->getUser($user);
645
+        $cloudId = $user->getCloudId();
646
+        $message = "Use my Federated Cloud ID to share with me: " . $cloudId;
647
+        $signature = $this->signMessage($user, $message);
648
+
649
+        $code = $message . ' ' . $signature;
650
+        $codeMd5 = $message . ' ' . md5($signature);
651
+
652
+        switch ($account) {
653
+            case 'verify-twitter':
654
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
655
+                $msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
656
+                $code = $codeMd5;
657
+                $type = AccountManager::PROPERTY_TWITTER;
658
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
659
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
660
+                break;
661
+            case 'verify-website':
662
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
663
+                $msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
664
+                $type = AccountManager::PROPERTY_WEBSITE;
665
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
666
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
667
+                break;
668
+            default:
669
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
670
+        }
671
+
672
+        if ($onlyVerificationCode === false) {
673
+            $this->accountManager->updateUser($user, $accountData);
674
+
675
+            $this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
676
+                [
677
+                    'verificationCode' => $code,
678
+                    'data' => $data,
679
+                    'type' => $type,
680
+                    'uid' => $user->getUID(),
681
+                    'try' => 0,
682
+                    'lastRun' => $this->getCurrentTime()
683
+                ]
684
+            );
685
+        }
686
+
687
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
688
+    }
689
+
690
+    /**
691
+     * get current timestamp
692
+     *
693
+     * @return int
694
+     */
695
+    protected function getCurrentTime() {
696
+        return time();
697
+    }
698
+
699
+    /**
700
+     * sign message with users private key
701
+     *
702
+     * @param IUser $user
703
+     * @param string $message
704
+     *
705
+     * @return string base64 encoded signature
706
+     */
707
+    protected function signMessage(IUser $user, $message) {
708
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
709
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
710
+        $signatureBase64 = base64_encode($signature);
711
+
712
+        return $signatureBase64;
713
+    }
714
+
715
+    /**
716
+     * @NoAdminRequired
717
+     * @NoSubadminRequired
718
+     * @PasswordConfirmationRequired
719
+     *
720
+     * @param string $avatarScope
721
+     * @param string $displayname
722
+     * @param string $displaynameScope
723
+     * @param string $phone
724
+     * @param string $phoneScope
725
+     * @param string $email
726
+     * @param string $emailScope
727
+     * @param string $website
728
+     * @param string $websiteScope
729
+     * @param string $address
730
+     * @param string $addressScope
731
+     * @param string $twitter
732
+     * @param string $twitterScope
733
+     * @return DataResponse
734
+     */
735
+    public function setUserSettings($avatarScope,
736
+                                    $displayname,
737
+                                    $displaynameScope,
738
+                                    $phone,
739
+                                    $phoneScope,
740
+                                    $email,
741
+                                    $emailScope,
742
+                                    $website,
743
+                                    $websiteScope,
744
+                                    $address,
745
+                                    $addressScope,
746
+                                    $twitter,
747
+                                    $twitterScope
748
+    ) {
749
+
750
+        if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
751
+            return new DataResponse(
752
+                [
753
+                    'status' => 'error',
754
+                    'data' => [
755
+                        'message' => (string)$this->l10n->t('Invalid mail address')
756
+                    ]
757
+                ],
758
+                Http::STATUS_UNPROCESSABLE_ENTITY
759
+            );
760
+        }
761
+
762
+        $user = $this->userSession->getUser();
763
+
764
+        $data = $this->accountManager->getUser($user);
765
+
766
+        $data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
767
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
768
+            $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
769
+            $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
770
+        }
771
+
772
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
773
+            $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
774
+            $shareProvider = $federatedFileSharing->getFederatedShareProvider();
775
+            if ($shareProvider->isLookupServerUploadEnabled()) {
776
+                $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
777
+                $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
778
+                $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
779
+                $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
780
+            }
781
+        }
782
+
783
+        try {
784
+            $this->saveUserSettings($user, $data);
785
+            return new DataResponse(
786
+                [
787
+                    'status' => 'success',
788
+                    'data' => [
789
+                        'userId' => $user->getUID(),
790
+                        'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
791
+                        'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
792
+                        'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
793
+                        'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
794
+                        'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
795
+                        'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
796
+                        'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
797
+                        'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
798
+                        'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
799
+                        'message' => (string)$this->l10n->t('Settings saved')
800
+                    ]
801
+                ],
802
+                Http::STATUS_OK
803
+            );
804
+        } catch (ForbiddenException $e) {
805
+            return new DataResponse([
806
+                'status' => 'error',
807
+                'data' => [
808
+                    'message' => $e->getMessage()
809
+                ],
810
+            ]);
811
+        }
812
+
813
+    }
814
+
815
+
816
+    /**
817
+     * update account manager with new user data
818
+     *
819
+     * @param IUser $user
820
+     * @param array $data
821
+     * @throws ForbiddenException
822
+     */
823
+    protected function saveUserSettings(IUser $user, $data) {
824
+
825
+        // keep the user back-end up-to-date with the latest display name and email
826
+        // address
827
+        $oldDisplayName = $user->getDisplayName();
828
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
829
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
830
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
831
+        ) {
832
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
833
+            if ($result === false) {
834
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
835
+            }
836
+        }
837
+
838
+        $oldEmailAddress = $user->getEMailAddress();
839
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
840
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
841
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
842
+        ) {
843
+            // this is the only permission a backend provides and is also used
844
+            // for the permission of setting a email address
845
+            if (!$user->canChangeDisplayName()) {
846
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
847
+            }
848
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
849
+        }
850
+
851
+        $this->accountManager->updateUser($user, $data);
852
+    }
853
+
854
+    /**
855
+     * Count all unique users visible for the current admin/subadmin.
856
+     *
857
+     * @NoAdminRequired
858
+     *
859
+     * @return DataResponse
860
+     */
861
+    public function stats() {
862
+        $userCount = 0;
863
+        if ($this->isAdmin) {
864
+            $countByBackend = $this->userManager->countUsers();
865
+
866
+            if (!empty($countByBackend)) {
867
+                foreach ($countByBackend as $count) {
868
+                    $userCount += $count;
869
+                }
870
+            }
871
+        } else {
872
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
873
+
874
+            $uniqueUsers = [];
875
+            foreach ($groups as $group) {
876
+                foreach ($group->getUsers() as $uid => $displayName) {
877
+                    $uniqueUsers[$uid] = true;
878
+                }
879
+            }
880
+
881
+            $userCount = count($uniqueUsers);
882
+        }
883
+
884
+        return new DataResponse(
885
+            [
886
+                'totalUsers' => $userCount
887
+            ]
888
+        );
889
+    }
890
+
891
+
892
+    /**
893
+     * Set the displayName of a user
894
+     *
895
+     * @NoAdminRequired
896
+     * @NoSubadminRequired
897
+     * @PasswordConfirmationRequired
898
+     * @todo merge into saveUserSettings
899
+     *
900
+     * @param string $username
901
+     * @param string $displayName
902
+     * @return DataResponse
903
+     */
904
+    public function setDisplayName($username, $displayName) {
905
+        $currentUser = $this->userSession->getUser();
906
+        $user = $this->userManager->get($username);
907
+
908
+        if ($user === null ||
909
+            !$user->canChangeDisplayName() ||
910
+            (
911
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
912
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
913
+                $currentUser->getUID() !== $username
914
+
915
+            )
916
+        ) {
917
+            return new DataResponse([
918
+                'status' => 'error',
919
+                'data' => [
920
+                    'message' => $this->l10n->t('Authentication error'),
921
+                ],
922
+            ]);
923
+        }
924
+
925
+        $userData = $this->accountManager->getUser($user);
926
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
927
+
928
+
929
+        try {
930
+            $this->saveUserSettings($user, $userData);
931
+            return new DataResponse([
932
+                'status' => 'success',
933
+                'data' => [
934
+                    'message' => $this->l10n->t('Your full name has been changed.'),
935
+                    'username' => $username,
936
+                    'displayName' => $displayName,
937
+                ],
938
+            ]);
939
+        } catch (ForbiddenException $e) {
940
+            return new DataResponse([
941
+                'status' => 'error',
942
+                'data' => [
943
+                    'message' => $e->getMessage(),
944
+                    'displayName' => $user->getDisplayName(),
945
+                ],
946
+            ]);
947
+        }
948
+    }
949
+
950
+    /**
951
+     * Set the mail address of a user
952
+     *
953
+     * @NoAdminRequired
954
+     * @NoSubadminRequired
955
+     * @PasswordConfirmationRequired
956
+     *
957
+     * @param string $id
958
+     * @param string $mailAddress
959
+     * @return DataResponse
960
+     */
961
+    public function setEMailAddress($id, $mailAddress) {
962
+        $user = $this->userManager->get($id);
963
+        if (!$this->isAdmin
964
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
965
+        ) {
966
+            return new DataResponse(
967
+                [
968
+                    'status' => 'error',
969
+                    'data' => [
970
+                        'message' => (string)$this->l10n->t('Forbidden')
971
+                    ]
972
+                ],
973
+                Http::STATUS_FORBIDDEN
974
+            );
975
+        }
976
+
977
+        if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
978
+            return new DataResponse(
979
+                [
980
+                    'status' => 'error',
981
+                    'data' => [
982
+                        'message' => (string)$this->l10n->t('Invalid mail address')
983
+                    ]
984
+                ],
985
+                Http::STATUS_UNPROCESSABLE_ENTITY
986
+            );
987
+        }
988
+
989
+        if (!$user) {
990
+            return new DataResponse(
991
+                [
992
+                    'status' => 'error',
993
+                    'data' => [
994
+                        'message' => (string)$this->l10n->t('Invalid user')
995
+                    ]
996
+                ],
997
+                Http::STATUS_UNPROCESSABLE_ENTITY
998
+            );
999
+        }
1000
+        // this is the only permission a backend provides and is also used
1001
+        // for the permission of setting a email address
1002
+        if (!$user->canChangeDisplayName()) {
1003
+            return new DataResponse(
1004
+                [
1005
+                    'status' => 'error',
1006
+                    'data' => [
1007
+                        'message' => (string)$this->l10n->t('Unable to change mail address')
1008
+                    ]
1009
+                ],
1010
+                Http::STATUS_FORBIDDEN
1011
+            );
1012
+        }
1013
+
1014
+        $userData = $this->accountManager->getUser($user);
1015
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
1016
+
1017
+        try {
1018
+            $this->saveUserSettings($user, $userData);
1019
+            return new DataResponse(
1020
+                [
1021
+                    'status' => 'success',
1022
+                    'data' => [
1023
+                        'username' => $id,
1024
+                        'mailAddress' => $mailAddress,
1025
+                        'message' => (string)$this->l10n->t('Email saved')
1026
+                    ]
1027
+                ],
1028
+                Http::STATUS_OK
1029
+            );
1030
+        } catch (ForbiddenException $e) {
1031
+            return new DataResponse([
1032
+                'status' => 'error',
1033
+                'data' => [
1034
+                    'message' => $e->getMessage()
1035
+                ],
1036
+            ]);
1037
+        }
1038
+    }
1039 1039
 
1040 1040
 }
Please login to merge, or discard this patch.
apps/encryption/lib/AppInfo/Application.php 1 patch
Indentation   +222 added lines, -222 removed lines patch added patch discarded remove patch
@@ -48,226 +48,226 @@
 block discarded – undo
48 48
 
49 49
 class Application extends \OCP\AppFramework\App {
50 50
 
51
-	/** @var IManager */
52
-	private $encryptionManager;
53
-	/** @var IConfig */
54
-	private $config;
55
-
56
-	/**
57
-	 * @param array $urlParams
58
-	 * @param bool $encryptionSystemReady
59
-	 */
60
-	public function __construct($urlParams = array(), $encryptionSystemReady = true) {
61
-		parent::__construct('encryption', $urlParams);
62
-		$this->encryptionManager = \OC::$server->getEncryptionManager();
63
-		$this->config = \OC::$server->getConfig();
64
-		$this->registerServices();
65
-		if($encryptionSystemReady === false) {
66
-			/** @var Session $session */
67
-			$session = $this->getContainer()->query('Session');
68
-			$session->setStatus(Session::RUN_MIGRATION);
69
-		}
70
-
71
-	}
72
-
73
-	public function setUp() {
74
-		if ($this->encryptionManager->isEnabled()) {
75
-			/** @var Setup $setup */
76
-			$setup = $this->getContainer()->query('UserSetup');
77
-			$setup->setupSystem();
78
-		}
79
-	}
80
-
81
-	/**
82
-	 * register hooks
83
-	 */
84
-	public function registerHooks() {
85
-		if (!$this->config->getSystemValue('maintenance', false)) {
86
-
87
-			$container = $this->getContainer();
88
-			$server = $container->getServer();
89
-			// Register our hooks and fire them.
90
-			$hookManager = new HookManager();
91
-
92
-			$hookManager->registerHook([
93
-				new UserHooks($container->query('KeyManager'),
94
-					$server->getUserManager(),
95
-					$server->getLogger(),
96
-					$container->query('UserSetup'),
97
-					$server->getUserSession(),
98
-					$container->query('Util'),
99
-					$container->query('Session'),
100
-					$container->query('Crypt'),
101
-					$container->query('Recovery'))
102
-			]);
103
-
104
-			$hookManager->fireHooks();
105
-
106
-		} else {
107
-			// Logout user if we are in maintenance to force re-login
108
-			$this->getContainer()->getServer()->getUserSession()->logout();
109
-		}
110
-	}
111
-
112
-	public function registerEncryptionModule() {
113
-		$container = $this->getContainer();
114
-
115
-
116
-		$this->encryptionManager->registerEncryptionModule(
117
-			Encryption::ID,
118
-			Encryption::DISPLAY_NAME,
119
-			function() use ($container) {
120
-
121
-			return new Encryption(
122
-				$container->query('Crypt'),
123
-				$container->query('KeyManager'),
124
-				$container->query('Util'),
125
-				$container->query('Session'),
126
-				$container->query('EncryptAll'),
127
-				$container->query('DecryptAll'),
128
-				$container->getServer()->getLogger(),
129
-				$container->getServer()->getL10N($container->getAppName())
130
-			);
131
-		});
132
-
133
-	}
134
-
135
-	public function registerServices() {
136
-		$container = $this->getContainer();
137
-
138
-		$container->registerService('Crypt',
139
-			function (IAppContainer $c) {
140
-				$server = $c->getServer();
141
-				return new Crypt($server->getLogger(),
142
-					$server->getUserSession(),
143
-					$server->getConfig(),
144
-					$server->getL10N($c->getAppName()));
145
-			});
146
-
147
-		$container->registerService('Session',
148
-			function (IAppContainer $c) {
149
-				$server = $c->getServer();
150
-				return new Session($server->getSession());
151
-			}
152
-		);
153
-
154
-		$container->registerService('KeyManager',
155
-			function (IAppContainer $c) {
156
-				$server = $c->getServer();
157
-
158
-				return new KeyManager($server->getEncryptionKeyStorage(),
159
-					$c->query('Crypt'),
160
-					$server->getConfig(),
161
-					$server->getUserSession(),
162
-					new Session($server->getSession()),
163
-					$server->getLogger(),
164
-					$c->query('Util')
165
-				);
166
-			});
167
-
168
-		$container->registerService('Recovery',
169
-			function (IAppContainer $c) {
170
-				$server = $c->getServer();
171
-
172
-				return new Recovery(
173
-					$server->getUserSession(),
174
-					$c->query('Crypt'),
175
-					$server->getSecureRandom(),
176
-					$c->query('KeyManager'),
177
-					$server->getConfig(),
178
-					$server->getEncryptionKeyStorage(),
179
-					$server->getEncryptionFilesHelper(),
180
-					new View());
181
-			});
182
-
183
-		$container->registerService('RecoveryController', function (IAppContainer $c) {
184
-			$server = $c->getServer();
185
-			return new RecoveryController(
186
-				$c->getAppName(),
187
-				$server->getRequest(),
188
-				$server->getConfig(),
189
-				$server->getL10N($c->getAppName()),
190
-				$c->query('Recovery'));
191
-		});
192
-
193
-		$container->registerService('StatusController', function (IAppContainer $c) {
194
-			$server = $c->getServer();
195
-			return new StatusController(
196
-				$c->getAppName(),
197
-				$server->getRequest(),
198
-				$server->getL10N($c->getAppName()),
199
-				$c->query('Session'),
200
-				$server->getEncryptionManager()
201
-			);
202
-		});
203
-
204
-		$container->registerService('SettingsController', function (IAppContainer $c) {
205
-			$server = $c->getServer();
206
-			return new SettingsController(
207
-				$c->getAppName(),
208
-				$server->getRequest(),
209
-				$server->getL10N($c->getAppName()),
210
-				$server->getUserManager(),
211
-				$server->getUserSession(),
212
-				$c->query('KeyManager'),
213
-				$c->query('Crypt'),
214
-				$c->query('Session'),
215
-				$server->getSession(),
216
-				$c->query('Util')
217
-			);
218
-		});
219
-
220
-		$container->registerService('UserSetup',
221
-			function (IAppContainer $c) {
222
-				$server = $c->getServer();
223
-				return new Setup($server->getLogger(),
224
-					$server->getUserSession(),
225
-					$c->query('Crypt'),
226
-					$c->query('KeyManager'));
227
-			});
228
-
229
-		$container->registerService('Util',
230
-			function (IAppContainer $c) {
231
-				$server = $c->getServer();
232
-
233
-				return new Util(
234
-					new View(),
235
-					$c->query('Crypt'),
236
-					$server->getLogger(),
237
-					$server->getUserSession(),
238
-					$server->getConfig(),
239
-					$server->getUserManager());
240
-			});
241
-
242
-		$container->registerService('EncryptAll',
243
-			function (IAppContainer $c) {
244
-				$server = $c->getServer();
245
-				return new EncryptAll(
246
-					$c->query('UserSetup'),
247
-					$c->getServer()->getUserManager(),
248
-					new View(),
249
-					$c->query('KeyManager'),
250
-					$c->query('Util'),
251
-					$server->getConfig(),
252
-					$server->getMailer(),
253
-					$server->getL10N('encryption'),
254
-					new QuestionHelper(),
255
-					$server->getSecureRandom()
256
-				);
257
-			}
258
-		);
259
-
260
-		$container->registerService('DecryptAll',
261
-			function (IAppContainer $c) {
262
-				return new DecryptAll(
263
-					$c->query('Util'),
264
-					$c->query('KeyManager'),
265
-					$c->query('Crypt'),
266
-					$c->query('Session'),
267
-					new QuestionHelper()
268
-				);
269
-			}
270
-		);
271
-
272
-	}
51
+    /** @var IManager */
52
+    private $encryptionManager;
53
+    /** @var IConfig */
54
+    private $config;
55
+
56
+    /**
57
+     * @param array $urlParams
58
+     * @param bool $encryptionSystemReady
59
+     */
60
+    public function __construct($urlParams = array(), $encryptionSystemReady = true) {
61
+        parent::__construct('encryption', $urlParams);
62
+        $this->encryptionManager = \OC::$server->getEncryptionManager();
63
+        $this->config = \OC::$server->getConfig();
64
+        $this->registerServices();
65
+        if($encryptionSystemReady === false) {
66
+            /** @var Session $session */
67
+            $session = $this->getContainer()->query('Session');
68
+            $session->setStatus(Session::RUN_MIGRATION);
69
+        }
70
+
71
+    }
72
+
73
+    public function setUp() {
74
+        if ($this->encryptionManager->isEnabled()) {
75
+            /** @var Setup $setup */
76
+            $setup = $this->getContainer()->query('UserSetup');
77
+            $setup->setupSystem();
78
+        }
79
+    }
80
+
81
+    /**
82
+     * register hooks
83
+     */
84
+    public function registerHooks() {
85
+        if (!$this->config->getSystemValue('maintenance', false)) {
86
+
87
+            $container = $this->getContainer();
88
+            $server = $container->getServer();
89
+            // Register our hooks and fire them.
90
+            $hookManager = new HookManager();
91
+
92
+            $hookManager->registerHook([
93
+                new UserHooks($container->query('KeyManager'),
94
+                    $server->getUserManager(),
95
+                    $server->getLogger(),
96
+                    $container->query('UserSetup'),
97
+                    $server->getUserSession(),
98
+                    $container->query('Util'),
99
+                    $container->query('Session'),
100
+                    $container->query('Crypt'),
101
+                    $container->query('Recovery'))
102
+            ]);
103
+
104
+            $hookManager->fireHooks();
105
+
106
+        } else {
107
+            // Logout user if we are in maintenance to force re-login
108
+            $this->getContainer()->getServer()->getUserSession()->logout();
109
+        }
110
+    }
111
+
112
+    public function registerEncryptionModule() {
113
+        $container = $this->getContainer();
114
+
115
+
116
+        $this->encryptionManager->registerEncryptionModule(
117
+            Encryption::ID,
118
+            Encryption::DISPLAY_NAME,
119
+            function() use ($container) {
120
+
121
+            return new Encryption(
122
+                $container->query('Crypt'),
123
+                $container->query('KeyManager'),
124
+                $container->query('Util'),
125
+                $container->query('Session'),
126
+                $container->query('EncryptAll'),
127
+                $container->query('DecryptAll'),
128
+                $container->getServer()->getLogger(),
129
+                $container->getServer()->getL10N($container->getAppName())
130
+            );
131
+        });
132
+
133
+    }
134
+
135
+    public function registerServices() {
136
+        $container = $this->getContainer();
137
+
138
+        $container->registerService('Crypt',
139
+            function (IAppContainer $c) {
140
+                $server = $c->getServer();
141
+                return new Crypt($server->getLogger(),
142
+                    $server->getUserSession(),
143
+                    $server->getConfig(),
144
+                    $server->getL10N($c->getAppName()));
145
+            });
146
+
147
+        $container->registerService('Session',
148
+            function (IAppContainer $c) {
149
+                $server = $c->getServer();
150
+                return new Session($server->getSession());
151
+            }
152
+        );
153
+
154
+        $container->registerService('KeyManager',
155
+            function (IAppContainer $c) {
156
+                $server = $c->getServer();
157
+
158
+                return new KeyManager($server->getEncryptionKeyStorage(),
159
+                    $c->query('Crypt'),
160
+                    $server->getConfig(),
161
+                    $server->getUserSession(),
162
+                    new Session($server->getSession()),
163
+                    $server->getLogger(),
164
+                    $c->query('Util')
165
+                );
166
+            });
167
+
168
+        $container->registerService('Recovery',
169
+            function (IAppContainer $c) {
170
+                $server = $c->getServer();
171
+
172
+                return new Recovery(
173
+                    $server->getUserSession(),
174
+                    $c->query('Crypt'),
175
+                    $server->getSecureRandom(),
176
+                    $c->query('KeyManager'),
177
+                    $server->getConfig(),
178
+                    $server->getEncryptionKeyStorage(),
179
+                    $server->getEncryptionFilesHelper(),
180
+                    new View());
181
+            });
182
+
183
+        $container->registerService('RecoveryController', function (IAppContainer $c) {
184
+            $server = $c->getServer();
185
+            return new RecoveryController(
186
+                $c->getAppName(),
187
+                $server->getRequest(),
188
+                $server->getConfig(),
189
+                $server->getL10N($c->getAppName()),
190
+                $c->query('Recovery'));
191
+        });
192
+
193
+        $container->registerService('StatusController', function (IAppContainer $c) {
194
+            $server = $c->getServer();
195
+            return new StatusController(
196
+                $c->getAppName(),
197
+                $server->getRequest(),
198
+                $server->getL10N($c->getAppName()),
199
+                $c->query('Session'),
200
+                $server->getEncryptionManager()
201
+            );
202
+        });
203
+
204
+        $container->registerService('SettingsController', function (IAppContainer $c) {
205
+            $server = $c->getServer();
206
+            return new SettingsController(
207
+                $c->getAppName(),
208
+                $server->getRequest(),
209
+                $server->getL10N($c->getAppName()),
210
+                $server->getUserManager(),
211
+                $server->getUserSession(),
212
+                $c->query('KeyManager'),
213
+                $c->query('Crypt'),
214
+                $c->query('Session'),
215
+                $server->getSession(),
216
+                $c->query('Util')
217
+            );
218
+        });
219
+
220
+        $container->registerService('UserSetup',
221
+            function (IAppContainer $c) {
222
+                $server = $c->getServer();
223
+                return new Setup($server->getLogger(),
224
+                    $server->getUserSession(),
225
+                    $c->query('Crypt'),
226
+                    $c->query('KeyManager'));
227
+            });
228
+
229
+        $container->registerService('Util',
230
+            function (IAppContainer $c) {
231
+                $server = $c->getServer();
232
+
233
+                return new Util(
234
+                    new View(),
235
+                    $c->query('Crypt'),
236
+                    $server->getLogger(),
237
+                    $server->getUserSession(),
238
+                    $server->getConfig(),
239
+                    $server->getUserManager());
240
+            });
241
+
242
+        $container->registerService('EncryptAll',
243
+            function (IAppContainer $c) {
244
+                $server = $c->getServer();
245
+                return new EncryptAll(
246
+                    $c->query('UserSetup'),
247
+                    $c->getServer()->getUserManager(),
248
+                    new View(),
249
+                    $c->query('KeyManager'),
250
+                    $c->query('Util'),
251
+                    $server->getConfig(),
252
+                    $server->getMailer(),
253
+                    $server->getL10N('encryption'),
254
+                    new QuestionHelper(),
255
+                    $server->getSecureRandom()
256
+                );
257
+            }
258
+        );
259
+
260
+        $container->registerService('DecryptAll',
261
+            function (IAppContainer $c) {
262
+                return new DecryptAll(
263
+                    $c->query('Util'),
264
+                    $c->query('KeyManager'),
265
+                    $c->query('Crypt'),
266
+                    $c->query('Session'),
267
+                    new QuestionHelper()
268
+                );
269
+            }
270
+        );
271
+
272
+    }
273 273
 }
Please login to merge, or discard this patch.