Completed
Pull Request — master (#3869)
by Björn
13:19
created
settings/Controller/UsersController.php 1 patch
Indentation   +857 added lines, -857 removed lines patch added patch discarded remove patch
@@ -58,862 +58,862 @@
 block discarded – undo
58 58
  * @package OC\Settings\Controller
59 59
  */
60 60
 class UsersController extends Controller {
61
-	/** @var IL10N */
62
-	private $l10n;
63
-	/** @var IUserSession */
64
-	private $userSession;
65
-	/** @var bool */
66
-	private $isAdmin;
67
-	/** @var IUserManager */
68
-	private $userManager;
69
-	/** @var IGroupManager */
70
-	private $groupManager;
71
-	/** @var IConfig */
72
-	private $config;
73
-	/** @var ILogger */
74
-	private $log;
75
-	/** @var IMailer */
76
-	private $mailer;
77
-	/** @var bool contains the state of the encryption app */
78
-	private $isEncryptionAppEnabled;
79
-	/** @var bool contains the state of the admin recovery setting */
80
-	private $isRestoreEnabled = false;
81
-	/** @var IAvatarManager */
82
-	private $avatarManager;
83
-	/** @var AccountManager */
84
-	private $accountManager;
85
-	/** @var ISecureRandom */
86
-	private $secureRandom;
87
-	/** @var NewUserMailHelper */
88
-	private $newUserMailHelper;
89
-	/** @var ITimeFactory */
90
-	private $timeFactory;
91
-	/** @var ICrypto */
92
-	private $crypto;
93
-	/** @var Manager */
94
-	private $keyManager;
95
-	/** @var IJobList */
96
-	private $jobList;
97
-
98
-	/**
99
-	 * @param string $appName
100
-	 * @param IRequest $request
101
-	 * @param IUserManager $userManager
102
-	 * @param IGroupManager $groupManager
103
-	 * @param IUserSession $userSession
104
-	 * @param IConfig $config
105
-	 * @param bool $isAdmin
106
-	 * @param IL10N $l10n
107
-	 * @param ILogger $log
108
-	 * @param IMailer $mailer
109
-	 * @param IURLGenerator $urlGenerator
110
-	 * @param IAppManager $appManager
111
-	 * @param IAvatarManager $avatarManager
112
-	 * @param AccountManager $accountManager
113
-	 * @param ISecureRandom $secureRandom
114
-	 * @param NewUserMailHelper $newUserMailHelper
115
-	 * @param ITimeFactory $timeFactory
116
-	 * @param ICrypto $crypto
117
-	 * @param Manager $keyManager
118
-	 * @param IJobList $jobList
119
-	 */
120
-	public function __construct($appName,
121
-								IRequest $request,
122
-								IUserManager $userManager,
123
-								IGroupManager $groupManager,
124
-								IUserSession $userSession,
125
-								IConfig $config,
126
-								$isAdmin,
127
-								IL10N $l10n,
128
-								ILogger $log,
129
-								IMailer $mailer,
130
-								IURLGenerator $urlGenerator,
131
-								IAppManager $appManager,
132
-								IAvatarManager $avatarManager,
133
-								AccountManager $accountManager,
134
-								ISecureRandom $secureRandom,
135
-								NewUserMailHelper $newUserMailHelper,
136
-								ITimeFactory $timeFactory,
137
-								ICrypto $crypto,
138
-								Manager $keyManager,
139
-								IJobList $jobList) {
140
-		parent::__construct($appName, $request);
141
-		$this->userManager = $userManager;
142
-		$this->groupManager = $groupManager;
143
-		$this->userSession = $userSession;
144
-		$this->config = $config;
145
-		$this->isAdmin = $isAdmin;
146
-		$this->l10n = $l10n;
147
-		$this->log = $log;
148
-		$this->mailer = $mailer;
149
-		$this->avatarManager = $avatarManager;
150
-		$this->accountManager = $accountManager;
151
-		$this->secureRandom = $secureRandom;
152
-		$this->newUserMailHelper = $newUserMailHelper;
153
-		$this->timeFactory = $timeFactory;
154
-		$this->crypto = $crypto;
155
-		$this->keyManager = $keyManager;
156
-		$this->jobList = $jobList;
157
-
158
-		// check for encryption state - TODO see formatUserForIndex
159
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
160
-		if($this->isEncryptionAppEnabled) {
161
-			// putting this directly in empty is possible in PHP 5.5+
162
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
163
-			$this->isRestoreEnabled = !empty($result);
164
-		}
165
-	}
166
-
167
-	/**
168
-	 * @param IUser $user
169
-	 * @param array $userGroups
170
-	 * @return array
171
-	 */
172
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
173
-
174
-		// TODO: eliminate this encryption specific code below and somehow
175
-		// hook in additional user info from other apps
176
-
177
-		// recovery isn't possible if admin or user has it disabled and encryption
178
-		// is enabled - so we eliminate the else paths in the conditional tree
179
-		// below
180
-		$restorePossible = false;
181
-
182
-		if ($this->isEncryptionAppEnabled) {
183
-			if ($this->isRestoreEnabled) {
184
-				// check for the users recovery setting
185
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
186
-				// method call inside empty is possible with PHP 5.5+
187
-				$recoveryModeEnabled = !empty($recoveryMode);
188
-				if ($recoveryModeEnabled) {
189
-					// user also has recovery mode enabled
190
-					$restorePossible = true;
191
-				}
192
-			}
193
-		} else {
194
-			// recovery is possible if encryption is disabled (plain files are
195
-			// available)
196
-			$restorePossible = true;
197
-		}
198
-
199
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
200
-		foreach($subAdminGroups as $key => $subAdminGroup) {
201
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
202
-		}
203
-
204
-		$displayName = $user->getEMailAddress();
205
-		if (is_null($displayName)) {
206
-			$displayName = '';
207
-		}
208
-
209
-		$avatarAvailable = false;
210
-		try {
211
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
212
-		} catch (\Exception $e) {
213
-			//No avatar yet
214
-		}
215
-
216
-		return [
217
-			'name' => $user->getUID(),
218
-			'displayname' => $user->getDisplayName(),
219
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
220
-			'subadmin' => $subAdminGroups,
221
-			'quota' => $user->getQuota(),
222
-			'storageLocation' => $user->getHome(),
223
-			'lastLogin' => $user->getLastLogin() * 1000,
224
-			'backend' => $user->getBackendClassName(),
225
-			'email' => $displayName,
226
-			'isRestoreDisabled' => !$restorePossible,
227
-			'isAvatarAvailable' => $avatarAvailable,
228
-		];
229
-	}
230
-
231
-	/**
232
-	 * @param array $userIDs Array with schema [$uid => $displayName]
233
-	 * @return IUser[]
234
-	 */
235
-	private function getUsersForUID(array $userIDs) {
236
-		$users = [];
237
-		foreach ($userIDs as $uid => $displayName) {
238
-			$users[$uid] = $this->userManager->get($uid);
239
-		}
240
-		return $users;
241
-	}
242
-
243
-	/**
244
-	 * @NoAdminRequired
245
-	 *
246
-	 * @param int $offset
247
-	 * @param int $limit
248
-	 * @param string $gid GID to filter for
249
-	 * @param string $pattern Pattern to search for in the username
250
-	 * @param string $backend Backend to filter for (class-name)
251
-	 * @return DataResponse
252
-	 *
253
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
254
-	 */
255
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
256
-		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
257
-		if($gid === '_everyone') {
258
-			$gid = '';
259
-		}
260
-
261
-		// Remove backends
262
-		if(!empty($backend)) {
263
-			$activeBackends = $this->userManager->getBackends();
264
-			$this->userManager->clearBackends();
265
-			foreach($activeBackends as $singleActiveBackend) {
266
-				if($backend === get_class($singleActiveBackend)) {
267
-					$this->userManager->registerBackend($singleActiveBackend);
268
-					break;
269
-				}
270
-			}
271
-		}
272
-
273
-		$users = [];
274
-		if ($this->isAdmin) {
275
-
276
-			if($gid !== '') {
277
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
278
-			} else {
279
-				$batch = $this->userManager->search($pattern, $limit, $offset);
280
-			}
281
-
282
-			foreach ($batch as $user) {
283
-				$users[] = $this->formatUserForIndex($user);
284
-			}
285
-
286
-		} else {
287
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
288
-			// New class returns IGroup[] so convert back
289
-			$gids = [];
290
-			foreach ($subAdminOfGroups as $group) {
291
-				$gids[] = $group->getGID();
292
-			}
293
-			$subAdminOfGroups = $gids;
294
-
295
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
296
-			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
297
-				$gid = '';
298
-			}
299
-
300
-			// Batch all groups the user is subadmin of when a group is specified
301
-			$batch = [];
302
-			if($gid === '') {
303
-				foreach($subAdminOfGroups as $group) {
304
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
305
-
306
-					foreach($groupUsers as $uid => $displayName) {
307
-						$batch[$uid] = $displayName;
308
-					}
309
-				}
310
-			} else {
311
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
312
-			}
313
-			$batch = $this->getUsersForUID($batch);
314
-
315
-			foreach ($batch as $user) {
316
-				// Only add the groups, this user is a subadmin of
317
-				$userGroups = array_values(array_intersect(
318
-					$this->groupManager->getUserGroupIds($user),
319
-					$subAdminOfGroups
320
-				));
321
-				$users[] = $this->formatUserForIndex($user, $userGroups);
322
-			}
323
-		}
324
-
325
-		return new DataResponse($users);
326
-	}
327
-
328
-	/**
329
-	 * @NoAdminRequired
330
-	 * @PasswordConfirmationRequired
331
-	 *
332
-	 * @param string $username
333
-	 * @param string $password
334
-	 * @param array $groups
335
-	 * @param string $email
336
-	 * @return DataResponse
337
-	 */
338
-	public function create($username, $password, array $groups=array(), $email='') {
339
-		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
340
-			return new DataResponse(
341
-				array(
342
-					'message' => (string)$this->l10n->t('Invalid mail address')
343
-				),
344
-				Http::STATUS_UNPROCESSABLE_ENTITY
345
-			);
346
-		}
347
-
348
-		$currentUser = $this->userSession->getUser();
349
-
350
-		if (!$this->isAdmin) {
351
-			if (!empty($groups)) {
352
-				foreach ($groups as $key => $group) {
353
-					$groupObject = $this->groupManager->get($group);
354
-					if($groupObject === null) {
355
-						unset($groups[$key]);
356
-						continue;
357
-					}
358
-
359
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
360
-						unset($groups[$key]);
361
-					}
362
-				}
363
-			}
364
-
365
-			if (empty($groups)) {
366
-				return new DataResponse(
367
-					array(
368
-						'message' => $this->l10n->t('No valid group selected'),
369
-					),
370
-					Http::STATUS_FORBIDDEN
371
-				);
372
-			}
373
-		}
374
-
375
-		if ($this->userManager->userExists($username)) {
376
-			return new DataResponse(
377
-				array(
378
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
379
-				),
380
-				Http::STATUS_CONFLICT
381
-			);
382
-		}
383
-
384
-		$generatePasswordResetToken = false;
385
-		if ($password === '') {
386
-			if ($email === '') {
387
-				return new DataResponse(
388
-					array(
389
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
390
-					),
391
-					Http::STATUS_UNPROCESSABLE_ENTITY
392
-				);
393
-			}
394
-
395
-			$password = $this->secureRandom->generate(32);
396
-			$generatePasswordResetToken = true;
397
-		}
398
-
399
-		try {
400
-			$user = $this->userManager->createUser($username, $password);
401
-		} catch (\Exception $exception) {
402
-			$message = $exception->getMessage();
403
-			if (!$message) {
404
-				$message = $this->l10n->t('Unable to create user.');
405
-			}
406
-			return new DataResponse(
407
-				array(
408
-					'message' => (string) $message,
409
-				),
410
-				Http::STATUS_FORBIDDEN
411
-			);
412
-		}
413
-
414
-		if($user instanceof IUser) {
415
-			if($groups !== null) {
416
-				foreach($groups as $groupName) {
417
-					$group = $this->groupManager->get($groupName);
418
-
419
-					if(empty($group)) {
420
-						$group = $this->groupManager->createGroup($groupName);
421
-					}
422
-					$group->addUser($user);
423
-				}
424
-			}
425
-			/**
426
-			 * Send new user mail only if a mail is set
427
-			 */
428
-			if($email !== '') {
429
-				$user->setEMailAddress($email);
430
-				try {
431
-					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
432
-					$this->newUserMailHelper->sendMail($user, $emailTemplate);
433
-				} catch(\Exception $e) {
434
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
435
-				}
436
-			}
437
-			// fetch users groups
438
-			$userGroups = $this->groupManager->getUserGroupIds($user);
439
-
440
-			return new DataResponse(
441
-				$this->formatUserForIndex($user, $userGroups),
442
-				Http::STATUS_CREATED
443
-			);
444
-		}
445
-
446
-		return new DataResponse(
447
-			array(
448
-				'message' => (string)$this->l10n->t('Unable to create user.')
449
-			),
450
-			Http::STATUS_FORBIDDEN
451
-		);
452
-
453
-	}
454
-
455
-	/**
456
-	 * @NoAdminRequired
457
-	 * @PasswordConfirmationRequired
458
-	 *
459
-	 * @param string $id
460
-	 * @return DataResponse
461
-	 */
462
-	public function destroy($id) {
463
-		$userId = $this->userSession->getUser()->getUID();
464
-		$user = $this->userManager->get($id);
465
-
466
-		if($userId === $id) {
467
-			return new DataResponse(
468
-				array(
469
-					'status' => 'error',
470
-					'data' => array(
471
-						'message' => (string)$this->l10n->t('Unable to delete user.')
472
-					)
473
-				),
474
-				Http::STATUS_FORBIDDEN
475
-			);
476
-		}
477
-
478
-		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
479
-			return new DataResponse(
480
-				array(
481
-					'status' => 'error',
482
-					'data' => array(
483
-						'message' => (string)$this->l10n->t('Authentication error')
484
-					)
485
-				),
486
-				Http::STATUS_FORBIDDEN
487
-			);
488
-		}
489
-
490
-		if($user) {
491
-			if($user->delete()) {
492
-				return new DataResponse(
493
-					array(
494
-						'status' => 'success',
495
-						'data' => array(
496
-							'username' => $id
497
-						)
498
-					),
499
-					Http::STATUS_NO_CONTENT
500
-				);
501
-			}
502
-		}
503
-
504
-		return new DataResponse(
505
-			array(
506
-				'status' => 'error',
507
-				'data' => array(
508
-					'message' => (string)$this->l10n->t('Unable to delete user.')
509
-				)
510
-			),
511
-			Http::STATUS_FORBIDDEN
512
-		);
513
-	}
514
-
515
-	/**
516
-	 * @NoAdminRequired
517
-	 * @NoSubadminRequired
518
-	 * @PasswordConfirmationRequired
519
-	 *
520
-	 * @param string $account
521
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
522
-	 * @return DataResponse
523
-	 */
524
-	public function getVerificationCode($account, $onlyVerificationCode) {
525
-
526
-		$user = $this->userSession->getUser();
527
-
528
-		if ($user === null) {
529
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
530
-		}
531
-
532
-		$accountData = $this->accountManager->getUser($user);
533
-		$cloudId = $user->getCloudId();
534
-		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
535
-		$signature = $this->signMessage($user, $message);
536
-
537
-		$code = $message . ' ' . $signature;
538
-		$codeMd5 = $message . ' ' . md5($signature);
539
-
540
-		switch ($account) {
541
-			case 'verify-twitter':
542
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
543
-				$msg = $this->l10n->t('In order to verify your Twitter account post following tweet on Twitter (please make sure to post it without any line breaks):');
544
-				$code = $codeMd5;
545
-				$type = AccountManager::PROPERTY_TWITTER;
546
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
547
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
548
-				break;
549
-			case 'verify-website':
550
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
551
-				$msg = $this->l10n->t('In order to verify your Website store following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
552
-				$type = AccountManager::PROPERTY_WEBSITE;
553
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
554
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
555
-				break;
556
-			default:
557
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
558
-		}
559
-
560
-		if ($onlyVerificationCode === false) {
561
-			$this->accountManager->updateUser($user, $accountData);
562
-
563
-			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
564
-				[
565
-					'verificationCode' => $code,
566
-					'data' => $data,
567
-					'type' => $type,
568
-					'uid' => $user->getUID(),
569
-					'try' => 0,
570
-					'lastRun' => $this->getCurrentTime()
571
-				]
572
-			);
573
-		}
574
-
575
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
576
-	}
577
-
578
-	/**
579
-	 * get current timestamp
580
-	 *
581
-	 * @return int
582
-	 */
583
-	protected function getCurrentTime() {
584
-		return time();
585
-	}
586
-
587
-	/**
588
-	 * sign message with users private key
589
-	 *
590
-	 * @param IUser $user
591
-	 * @param string $message
592
-	 *
593
-	 * @return string base64 encoded signature
594
-	 */
595
-	protected function signMessage(IUser $user, $message) {
596
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
597
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
598
-		$signatureBase64 = base64_encode($signature);
599
-
600
-		return $signatureBase64;
601
-	}
602
-
603
-	/**
604
-	 * @NoAdminRequired
605
-	 * @NoSubadminRequired
606
-	 * @PasswordConfirmationRequired
607
-	 *
608
-	 * @param string $avatarScope
609
-	 * @param string $displayname
610
-	 * @param string $displaynameScope
611
-	 * @param string $phone
612
-	 * @param string $phoneScope
613
-	 * @param string $email
614
-	 * @param string $emailScope
615
-	 * @param string $website
616
-	 * @param string $websiteScope
617
-	 * @param string $address
618
-	 * @param string $addressScope
619
-	 * @param string $twitter
620
-	 * @param string $twitterScope
621
-	 * @return DataResponse
622
-	 */
623
-	public function setUserSettings($avatarScope,
624
-									$displayname,
625
-									$displaynameScope,
626
-									$phone,
627
-									$phoneScope,
628
-									$email,
629
-									$emailScope,
630
-									$website,
631
-									$websiteScope,
632
-									$address,
633
-									$addressScope,
634
-									$twitter,
635
-									$twitterScope
636
-	) {
637
-
638
-		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
639
-			return new DataResponse(
640
-				array(
641
-					'status' => 'error',
642
-					'data' => array(
643
-						'message' => (string)$this->l10n->t('Invalid mail address')
644
-					)
645
-				),
646
-				Http::STATUS_UNPROCESSABLE_ENTITY
647
-			);
648
-		}
649
-
650
-		$data = [
651
-			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
652
-			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
653
-			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
654
-			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
655
-			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
656
-			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
657
-			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
658
-		];
659
-
660
-		$user = $this->userSession->getUser();
661
-
662
-		try {
663
-			$this->saveUserSettings($user, $data);
664
-			return new DataResponse(
665
-				array(
666
-					'status' => 'success',
667
-					'data' => array(
668
-						'userId' => $user->getUID(),
669
-						'avatarScope' => $avatarScope,
670
-						'displayname' => $displayname,
671
-						'displaynameScope' => $displaynameScope,
672
-						'email' => $email,
673
-						'emailScope' => $emailScope,
674
-						'website' => $website,
675
-						'websiteScope' => $websiteScope,
676
-						'address' => $address,
677
-						'addressScope' => $addressScope,
678
-						'message' => (string)$this->l10n->t('Settings saved')
679
-					)
680
-				),
681
-				Http::STATUS_OK
682
-			);
683
-		} catch (ForbiddenException $e) {
684
-			return new DataResponse([
685
-				'status' => 'error',
686
-				'data' => [
687
-					'message' => $e->getMessage()
688
-				],
689
-			]);
690
-		}
691
-
692
-	}
693
-
694
-
695
-	/**
696
-	 * update account manager with new user data
697
-	 *
698
-	 * @param IUser $user
699
-	 * @param array $data
700
-	 * @throws ForbiddenException
701
-	 */
702
-	protected function saveUserSettings(IUser $user, $data) {
703
-
704
-		// keep the user back-end up-to-date with the latest display name and email
705
-		// address
706
-		$oldDisplayName = $user->getDisplayName();
707
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
708
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
709
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
710
-		) {
711
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
712
-			if ($result === false) {
713
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
714
-			}
715
-		}
716
-
717
-		$oldEmailAddress = $user->getEMailAddress();
718
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
719
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
720
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
721
-		) {
722
-			// this is the only permission a backend provides and is also used
723
-			// for the permission of setting a email address
724
-			if (!$user->canChangeDisplayName()) {
725
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
726
-			}
727
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
728
-		}
729
-
730
-		$this->accountManager->updateUser($user, $data);
731
-	}
732
-
733
-	/**
734
-	 * Count all unique users visible for the current admin/subadmin.
735
-	 *
736
-	 * @NoAdminRequired
737
-	 *
738
-	 * @return DataResponse
739
-	 */
740
-	public function stats() {
741
-		$userCount = 0;
742
-		if ($this->isAdmin) {
743
-			$countByBackend = $this->userManager->countUsers();
744
-
745
-			if (!empty($countByBackend)) {
746
-				foreach ($countByBackend as $count) {
747
-					$userCount += $count;
748
-				}
749
-			}
750
-		} else {
751
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
752
-
753
-			$uniqueUsers = [];
754
-			foreach ($groups as $group) {
755
-				foreach($group->getUsers() as $uid => $displayName) {
756
-					$uniqueUsers[$uid] = true;
757
-				}
758
-			}
759
-
760
-			$userCount = count($uniqueUsers);
761
-		}
762
-
763
-		return new DataResponse(
764
-			[
765
-				'totalUsers' => $userCount
766
-			]
767
-		);
768
-	}
769
-
770
-
771
-	/**
772
-	 * Set the displayName of a user
773
-	 *
774
-	 * @NoAdminRequired
775
-	 * @NoSubadminRequired
776
-	 * @PasswordConfirmationRequired
777
-	 * @todo merge into saveUserSettings
778
-	 *
779
-	 * @param string $username
780
-	 * @param string $displayName
781
-	 * @return DataResponse
782
-	 */
783
-	public function setDisplayName($username, $displayName) {
784
-		$currentUser = $this->userSession->getUser();
785
-		$user = $this->userManager->get($username);
786
-
787
-		if ($user === null ||
788
-			!$user->canChangeDisplayName() ||
789
-			(
790
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
791
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
792
-				$currentUser->getUID() !== $username
793
-
794
-			)
795
-		) {
796
-			return new DataResponse([
797
-				'status' => 'error',
798
-				'data' => [
799
-					'message' => $this->l10n->t('Authentication error'),
800
-				],
801
-			]);
802
-		}
803
-
804
-		$userData = $this->accountManager->getUser($user);
805
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
806
-
807
-
808
-		try {
809
-			$this->saveUserSettings($user, $userData);
810
-			return new DataResponse([
811
-				'status' => 'success',
812
-				'data' => [
813
-					'message' => $this->l10n->t('Your full name has been changed.'),
814
-					'username' => $username,
815
-					'displayName' => $displayName,
816
-				],
817
-			]);
818
-		} catch (ForbiddenException $e) {
819
-			return new DataResponse([
820
-				'status' => 'error',
821
-				'data' => [
822
-					'message' => $e->getMessage(),
823
-					'displayName' => $user->getDisplayName(),
824
-				],
825
-			]);
826
-		}
827
-	}
828
-
829
-	/**
830
-	 * Set the mail address of a user
831
-	 *
832
-	 * @NoAdminRequired
833
-	 * @NoSubadminRequired
834
-	 * @PasswordConfirmationRequired
835
-	 *
836
-	 * @param string $id
837
-	 * @param string $mailAddress
838
-	 * @return DataResponse
839
-	 */
840
-	public function setEMailAddress($id, $mailAddress) {
841
-		$user = $this->userManager->get($id);
842
-		if (!$this->isAdmin
843
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
844
-		) {
845
-			return new DataResponse(
846
-				array(
847
-					'status' => 'error',
848
-					'data' => array(
849
-						'message' => (string)$this->l10n->t('Forbidden')
850
-					)
851
-				),
852
-				Http::STATUS_FORBIDDEN
853
-			);
854
-		}
855
-
856
-		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
857
-			return new DataResponse(
858
-				array(
859
-					'status' => 'error',
860
-					'data' => array(
861
-						'message' => (string)$this->l10n->t('Invalid mail address')
862
-					)
863
-				),
864
-				Http::STATUS_UNPROCESSABLE_ENTITY
865
-			);
866
-		}
867
-
868
-		if (!$user) {
869
-			return new DataResponse(
870
-				array(
871
-					'status' => 'error',
872
-					'data' => array(
873
-						'message' => (string)$this->l10n->t('Invalid user')
874
-					)
875
-				),
876
-				Http::STATUS_UNPROCESSABLE_ENTITY
877
-			);
878
-		}
879
-		// this is the only permission a backend provides and is also used
880
-		// for the permission of setting a email address
881
-		if (!$user->canChangeDisplayName()) {
882
-			return new DataResponse(
883
-				array(
884
-					'status' => 'error',
885
-					'data' => array(
886
-						'message' => (string)$this->l10n->t('Unable to change mail address')
887
-					)
888
-				),
889
-				Http::STATUS_FORBIDDEN
890
-			);
891
-		}
892
-
893
-		$userData = $this->accountManager->getUser($user);
894
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
895
-
896
-		try {
897
-			$this->saveUserSettings($user, $userData);
898
-			return new DataResponse(
899
-				array(
900
-					'status' => 'success',
901
-					'data' => array(
902
-						'username' => $id,
903
-						'mailAddress' => $mailAddress,
904
-						'message' => (string)$this->l10n->t('Email saved')
905
-					)
906
-				),
907
-				Http::STATUS_OK
908
-			);
909
-		} catch (ForbiddenException $e) {
910
-			return new DataResponse([
911
-				'status' => 'error',
912
-				'data' => [
913
-					'message' => $e->getMessage()
914
-				],
915
-			]);
916
-		}
917
-	}
61
+    /** @var IL10N */
62
+    private $l10n;
63
+    /** @var IUserSession */
64
+    private $userSession;
65
+    /** @var bool */
66
+    private $isAdmin;
67
+    /** @var IUserManager */
68
+    private $userManager;
69
+    /** @var IGroupManager */
70
+    private $groupManager;
71
+    /** @var IConfig */
72
+    private $config;
73
+    /** @var ILogger */
74
+    private $log;
75
+    /** @var IMailer */
76
+    private $mailer;
77
+    /** @var bool contains the state of the encryption app */
78
+    private $isEncryptionAppEnabled;
79
+    /** @var bool contains the state of the admin recovery setting */
80
+    private $isRestoreEnabled = false;
81
+    /** @var IAvatarManager */
82
+    private $avatarManager;
83
+    /** @var AccountManager */
84
+    private $accountManager;
85
+    /** @var ISecureRandom */
86
+    private $secureRandom;
87
+    /** @var NewUserMailHelper */
88
+    private $newUserMailHelper;
89
+    /** @var ITimeFactory */
90
+    private $timeFactory;
91
+    /** @var ICrypto */
92
+    private $crypto;
93
+    /** @var Manager */
94
+    private $keyManager;
95
+    /** @var IJobList */
96
+    private $jobList;
97
+
98
+    /**
99
+     * @param string $appName
100
+     * @param IRequest $request
101
+     * @param IUserManager $userManager
102
+     * @param IGroupManager $groupManager
103
+     * @param IUserSession $userSession
104
+     * @param IConfig $config
105
+     * @param bool $isAdmin
106
+     * @param IL10N $l10n
107
+     * @param ILogger $log
108
+     * @param IMailer $mailer
109
+     * @param IURLGenerator $urlGenerator
110
+     * @param IAppManager $appManager
111
+     * @param IAvatarManager $avatarManager
112
+     * @param AccountManager $accountManager
113
+     * @param ISecureRandom $secureRandom
114
+     * @param NewUserMailHelper $newUserMailHelper
115
+     * @param ITimeFactory $timeFactory
116
+     * @param ICrypto $crypto
117
+     * @param Manager $keyManager
118
+     * @param IJobList $jobList
119
+     */
120
+    public function __construct($appName,
121
+                                IRequest $request,
122
+                                IUserManager $userManager,
123
+                                IGroupManager $groupManager,
124
+                                IUserSession $userSession,
125
+                                IConfig $config,
126
+                                $isAdmin,
127
+                                IL10N $l10n,
128
+                                ILogger $log,
129
+                                IMailer $mailer,
130
+                                IURLGenerator $urlGenerator,
131
+                                IAppManager $appManager,
132
+                                IAvatarManager $avatarManager,
133
+                                AccountManager $accountManager,
134
+                                ISecureRandom $secureRandom,
135
+                                NewUserMailHelper $newUserMailHelper,
136
+                                ITimeFactory $timeFactory,
137
+                                ICrypto $crypto,
138
+                                Manager $keyManager,
139
+                                IJobList $jobList) {
140
+        parent::__construct($appName, $request);
141
+        $this->userManager = $userManager;
142
+        $this->groupManager = $groupManager;
143
+        $this->userSession = $userSession;
144
+        $this->config = $config;
145
+        $this->isAdmin = $isAdmin;
146
+        $this->l10n = $l10n;
147
+        $this->log = $log;
148
+        $this->mailer = $mailer;
149
+        $this->avatarManager = $avatarManager;
150
+        $this->accountManager = $accountManager;
151
+        $this->secureRandom = $secureRandom;
152
+        $this->newUserMailHelper = $newUserMailHelper;
153
+        $this->timeFactory = $timeFactory;
154
+        $this->crypto = $crypto;
155
+        $this->keyManager = $keyManager;
156
+        $this->jobList = $jobList;
157
+
158
+        // check for encryption state - TODO see formatUserForIndex
159
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
160
+        if($this->isEncryptionAppEnabled) {
161
+            // putting this directly in empty is possible in PHP 5.5+
162
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
163
+            $this->isRestoreEnabled = !empty($result);
164
+        }
165
+    }
166
+
167
+    /**
168
+     * @param IUser $user
169
+     * @param array $userGroups
170
+     * @return array
171
+     */
172
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
173
+
174
+        // TODO: eliminate this encryption specific code below and somehow
175
+        // hook in additional user info from other apps
176
+
177
+        // recovery isn't possible if admin or user has it disabled and encryption
178
+        // is enabled - so we eliminate the else paths in the conditional tree
179
+        // below
180
+        $restorePossible = false;
181
+
182
+        if ($this->isEncryptionAppEnabled) {
183
+            if ($this->isRestoreEnabled) {
184
+                // check for the users recovery setting
185
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
186
+                // method call inside empty is possible with PHP 5.5+
187
+                $recoveryModeEnabled = !empty($recoveryMode);
188
+                if ($recoveryModeEnabled) {
189
+                    // user also has recovery mode enabled
190
+                    $restorePossible = true;
191
+                }
192
+            }
193
+        } else {
194
+            // recovery is possible if encryption is disabled (plain files are
195
+            // available)
196
+            $restorePossible = true;
197
+        }
198
+
199
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
200
+        foreach($subAdminGroups as $key => $subAdminGroup) {
201
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
202
+        }
203
+
204
+        $displayName = $user->getEMailAddress();
205
+        if (is_null($displayName)) {
206
+            $displayName = '';
207
+        }
208
+
209
+        $avatarAvailable = false;
210
+        try {
211
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
212
+        } catch (\Exception $e) {
213
+            //No avatar yet
214
+        }
215
+
216
+        return [
217
+            'name' => $user->getUID(),
218
+            'displayname' => $user->getDisplayName(),
219
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
220
+            'subadmin' => $subAdminGroups,
221
+            'quota' => $user->getQuota(),
222
+            'storageLocation' => $user->getHome(),
223
+            'lastLogin' => $user->getLastLogin() * 1000,
224
+            'backend' => $user->getBackendClassName(),
225
+            'email' => $displayName,
226
+            'isRestoreDisabled' => !$restorePossible,
227
+            'isAvatarAvailable' => $avatarAvailable,
228
+        ];
229
+    }
230
+
231
+    /**
232
+     * @param array $userIDs Array with schema [$uid => $displayName]
233
+     * @return IUser[]
234
+     */
235
+    private function getUsersForUID(array $userIDs) {
236
+        $users = [];
237
+        foreach ($userIDs as $uid => $displayName) {
238
+            $users[$uid] = $this->userManager->get($uid);
239
+        }
240
+        return $users;
241
+    }
242
+
243
+    /**
244
+     * @NoAdminRequired
245
+     *
246
+     * @param int $offset
247
+     * @param int $limit
248
+     * @param string $gid GID to filter for
249
+     * @param string $pattern Pattern to search for in the username
250
+     * @param string $backend Backend to filter for (class-name)
251
+     * @return DataResponse
252
+     *
253
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
254
+     */
255
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
256
+        // FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
257
+        if($gid === '_everyone') {
258
+            $gid = '';
259
+        }
260
+
261
+        // Remove backends
262
+        if(!empty($backend)) {
263
+            $activeBackends = $this->userManager->getBackends();
264
+            $this->userManager->clearBackends();
265
+            foreach($activeBackends as $singleActiveBackend) {
266
+                if($backend === get_class($singleActiveBackend)) {
267
+                    $this->userManager->registerBackend($singleActiveBackend);
268
+                    break;
269
+                }
270
+            }
271
+        }
272
+
273
+        $users = [];
274
+        if ($this->isAdmin) {
275
+
276
+            if($gid !== '') {
277
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
278
+            } else {
279
+                $batch = $this->userManager->search($pattern, $limit, $offset);
280
+            }
281
+
282
+            foreach ($batch as $user) {
283
+                $users[] = $this->formatUserForIndex($user);
284
+            }
285
+
286
+        } else {
287
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
288
+            // New class returns IGroup[] so convert back
289
+            $gids = [];
290
+            foreach ($subAdminOfGroups as $group) {
291
+                $gids[] = $group->getGID();
292
+            }
293
+            $subAdminOfGroups = $gids;
294
+
295
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
296
+            if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
297
+                $gid = '';
298
+            }
299
+
300
+            // Batch all groups the user is subadmin of when a group is specified
301
+            $batch = [];
302
+            if($gid === '') {
303
+                foreach($subAdminOfGroups as $group) {
304
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
305
+
306
+                    foreach($groupUsers as $uid => $displayName) {
307
+                        $batch[$uid] = $displayName;
308
+                    }
309
+                }
310
+            } else {
311
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
312
+            }
313
+            $batch = $this->getUsersForUID($batch);
314
+
315
+            foreach ($batch as $user) {
316
+                // Only add the groups, this user is a subadmin of
317
+                $userGroups = array_values(array_intersect(
318
+                    $this->groupManager->getUserGroupIds($user),
319
+                    $subAdminOfGroups
320
+                ));
321
+                $users[] = $this->formatUserForIndex($user, $userGroups);
322
+            }
323
+        }
324
+
325
+        return new DataResponse($users);
326
+    }
327
+
328
+    /**
329
+     * @NoAdminRequired
330
+     * @PasswordConfirmationRequired
331
+     *
332
+     * @param string $username
333
+     * @param string $password
334
+     * @param array $groups
335
+     * @param string $email
336
+     * @return DataResponse
337
+     */
338
+    public function create($username, $password, array $groups=array(), $email='') {
339
+        if($email !== '' && !$this->mailer->validateMailAddress($email)) {
340
+            return new DataResponse(
341
+                array(
342
+                    'message' => (string)$this->l10n->t('Invalid mail address')
343
+                ),
344
+                Http::STATUS_UNPROCESSABLE_ENTITY
345
+            );
346
+        }
347
+
348
+        $currentUser = $this->userSession->getUser();
349
+
350
+        if (!$this->isAdmin) {
351
+            if (!empty($groups)) {
352
+                foreach ($groups as $key => $group) {
353
+                    $groupObject = $this->groupManager->get($group);
354
+                    if($groupObject === null) {
355
+                        unset($groups[$key]);
356
+                        continue;
357
+                    }
358
+
359
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
360
+                        unset($groups[$key]);
361
+                    }
362
+                }
363
+            }
364
+
365
+            if (empty($groups)) {
366
+                return new DataResponse(
367
+                    array(
368
+                        'message' => $this->l10n->t('No valid group selected'),
369
+                    ),
370
+                    Http::STATUS_FORBIDDEN
371
+                );
372
+            }
373
+        }
374
+
375
+        if ($this->userManager->userExists($username)) {
376
+            return new DataResponse(
377
+                array(
378
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
379
+                ),
380
+                Http::STATUS_CONFLICT
381
+            );
382
+        }
383
+
384
+        $generatePasswordResetToken = false;
385
+        if ($password === '') {
386
+            if ($email === '') {
387
+                return new DataResponse(
388
+                    array(
389
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
390
+                    ),
391
+                    Http::STATUS_UNPROCESSABLE_ENTITY
392
+                );
393
+            }
394
+
395
+            $password = $this->secureRandom->generate(32);
396
+            $generatePasswordResetToken = true;
397
+        }
398
+
399
+        try {
400
+            $user = $this->userManager->createUser($username, $password);
401
+        } catch (\Exception $exception) {
402
+            $message = $exception->getMessage();
403
+            if (!$message) {
404
+                $message = $this->l10n->t('Unable to create user.');
405
+            }
406
+            return new DataResponse(
407
+                array(
408
+                    'message' => (string) $message,
409
+                ),
410
+                Http::STATUS_FORBIDDEN
411
+            );
412
+        }
413
+
414
+        if($user instanceof IUser) {
415
+            if($groups !== null) {
416
+                foreach($groups as $groupName) {
417
+                    $group = $this->groupManager->get($groupName);
418
+
419
+                    if(empty($group)) {
420
+                        $group = $this->groupManager->createGroup($groupName);
421
+                    }
422
+                    $group->addUser($user);
423
+                }
424
+            }
425
+            /**
426
+             * Send new user mail only if a mail is set
427
+             */
428
+            if($email !== '') {
429
+                $user->setEMailAddress($email);
430
+                try {
431
+                    $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
432
+                    $this->newUserMailHelper->sendMail($user, $emailTemplate);
433
+                } catch(\Exception $e) {
434
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
435
+                }
436
+            }
437
+            // fetch users groups
438
+            $userGroups = $this->groupManager->getUserGroupIds($user);
439
+
440
+            return new DataResponse(
441
+                $this->formatUserForIndex($user, $userGroups),
442
+                Http::STATUS_CREATED
443
+            );
444
+        }
445
+
446
+        return new DataResponse(
447
+            array(
448
+                'message' => (string)$this->l10n->t('Unable to create user.')
449
+            ),
450
+            Http::STATUS_FORBIDDEN
451
+        );
452
+
453
+    }
454
+
455
+    /**
456
+     * @NoAdminRequired
457
+     * @PasswordConfirmationRequired
458
+     *
459
+     * @param string $id
460
+     * @return DataResponse
461
+     */
462
+    public function destroy($id) {
463
+        $userId = $this->userSession->getUser()->getUID();
464
+        $user = $this->userManager->get($id);
465
+
466
+        if($userId === $id) {
467
+            return new DataResponse(
468
+                array(
469
+                    'status' => 'error',
470
+                    'data' => array(
471
+                        'message' => (string)$this->l10n->t('Unable to delete user.')
472
+                    )
473
+                ),
474
+                Http::STATUS_FORBIDDEN
475
+            );
476
+        }
477
+
478
+        if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
479
+            return new DataResponse(
480
+                array(
481
+                    'status' => 'error',
482
+                    'data' => array(
483
+                        'message' => (string)$this->l10n->t('Authentication error')
484
+                    )
485
+                ),
486
+                Http::STATUS_FORBIDDEN
487
+            );
488
+        }
489
+
490
+        if($user) {
491
+            if($user->delete()) {
492
+                return new DataResponse(
493
+                    array(
494
+                        'status' => 'success',
495
+                        'data' => array(
496
+                            'username' => $id
497
+                        )
498
+                    ),
499
+                    Http::STATUS_NO_CONTENT
500
+                );
501
+            }
502
+        }
503
+
504
+        return new DataResponse(
505
+            array(
506
+                'status' => 'error',
507
+                'data' => array(
508
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
509
+                )
510
+            ),
511
+            Http::STATUS_FORBIDDEN
512
+        );
513
+    }
514
+
515
+    /**
516
+     * @NoAdminRequired
517
+     * @NoSubadminRequired
518
+     * @PasswordConfirmationRequired
519
+     *
520
+     * @param string $account
521
+     * @param bool $onlyVerificationCode only return verification code without updating the data
522
+     * @return DataResponse
523
+     */
524
+    public function getVerificationCode($account, $onlyVerificationCode) {
525
+
526
+        $user = $this->userSession->getUser();
527
+
528
+        if ($user === null) {
529
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
530
+        }
531
+
532
+        $accountData = $this->accountManager->getUser($user);
533
+        $cloudId = $user->getCloudId();
534
+        $message = "Use my Federated Cloud ID to share with me: " . $cloudId;
535
+        $signature = $this->signMessage($user, $message);
536
+
537
+        $code = $message . ' ' . $signature;
538
+        $codeMd5 = $message . ' ' . md5($signature);
539
+
540
+        switch ($account) {
541
+            case 'verify-twitter':
542
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
543
+                $msg = $this->l10n->t('In order to verify your Twitter account post following tweet on Twitter (please make sure to post it without any line breaks):');
544
+                $code = $codeMd5;
545
+                $type = AccountManager::PROPERTY_TWITTER;
546
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
547
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
548
+                break;
549
+            case 'verify-website':
550
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
551
+                $msg = $this->l10n->t('In order to verify your Website store following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
552
+                $type = AccountManager::PROPERTY_WEBSITE;
553
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
554
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
555
+                break;
556
+            default:
557
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
558
+        }
559
+
560
+        if ($onlyVerificationCode === false) {
561
+            $this->accountManager->updateUser($user, $accountData);
562
+
563
+            $this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
564
+                [
565
+                    'verificationCode' => $code,
566
+                    'data' => $data,
567
+                    'type' => $type,
568
+                    'uid' => $user->getUID(),
569
+                    'try' => 0,
570
+                    'lastRun' => $this->getCurrentTime()
571
+                ]
572
+            );
573
+        }
574
+
575
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
576
+    }
577
+
578
+    /**
579
+     * get current timestamp
580
+     *
581
+     * @return int
582
+     */
583
+    protected function getCurrentTime() {
584
+        return time();
585
+    }
586
+
587
+    /**
588
+     * sign message with users private key
589
+     *
590
+     * @param IUser $user
591
+     * @param string $message
592
+     *
593
+     * @return string base64 encoded signature
594
+     */
595
+    protected function signMessage(IUser $user, $message) {
596
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
597
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
598
+        $signatureBase64 = base64_encode($signature);
599
+
600
+        return $signatureBase64;
601
+    }
602
+
603
+    /**
604
+     * @NoAdminRequired
605
+     * @NoSubadminRequired
606
+     * @PasswordConfirmationRequired
607
+     *
608
+     * @param string $avatarScope
609
+     * @param string $displayname
610
+     * @param string $displaynameScope
611
+     * @param string $phone
612
+     * @param string $phoneScope
613
+     * @param string $email
614
+     * @param string $emailScope
615
+     * @param string $website
616
+     * @param string $websiteScope
617
+     * @param string $address
618
+     * @param string $addressScope
619
+     * @param string $twitter
620
+     * @param string $twitterScope
621
+     * @return DataResponse
622
+     */
623
+    public function setUserSettings($avatarScope,
624
+                                    $displayname,
625
+                                    $displaynameScope,
626
+                                    $phone,
627
+                                    $phoneScope,
628
+                                    $email,
629
+                                    $emailScope,
630
+                                    $website,
631
+                                    $websiteScope,
632
+                                    $address,
633
+                                    $addressScope,
634
+                                    $twitter,
635
+                                    $twitterScope
636
+    ) {
637
+
638
+        if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
639
+            return new DataResponse(
640
+                array(
641
+                    'status' => 'error',
642
+                    'data' => array(
643
+                        'message' => (string)$this->l10n->t('Invalid mail address')
644
+                    )
645
+                ),
646
+                Http::STATUS_UNPROCESSABLE_ENTITY
647
+            );
648
+        }
649
+
650
+        $data = [
651
+            AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
652
+            AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
653
+            AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
654
+            AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
655
+            AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
656
+            AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
657
+            AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
658
+        ];
659
+
660
+        $user = $this->userSession->getUser();
661
+
662
+        try {
663
+            $this->saveUserSettings($user, $data);
664
+            return new DataResponse(
665
+                array(
666
+                    'status' => 'success',
667
+                    'data' => array(
668
+                        'userId' => $user->getUID(),
669
+                        'avatarScope' => $avatarScope,
670
+                        'displayname' => $displayname,
671
+                        'displaynameScope' => $displaynameScope,
672
+                        'email' => $email,
673
+                        'emailScope' => $emailScope,
674
+                        'website' => $website,
675
+                        'websiteScope' => $websiteScope,
676
+                        'address' => $address,
677
+                        'addressScope' => $addressScope,
678
+                        'message' => (string)$this->l10n->t('Settings saved')
679
+                    )
680
+                ),
681
+                Http::STATUS_OK
682
+            );
683
+        } catch (ForbiddenException $e) {
684
+            return new DataResponse([
685
+                'status' => 'error',
686
+                'data' => [
687
+                    'message' => $e->getMessage()
688
+                ],
689
+            ]);
690
+        }
691
+
692
+    }
693
+
694
+
695
+    /**
696
+     * update account manager with new user data
697
+     *
698
+     * @param IUser $user
699
+     * @param array $data
700
+     * @throws ForbiddenException
701
+     */
702
+    protected function saveUserSettings(IUser $user, $data) {
703
+
704
+        // keep the user back-end up-to-date with the latest display name and email
705
+        // address
706
+        $oldDisplayName = $user->getDisplayName();
707
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
708
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
709
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
710
+        ) {
711
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
712
+            if ($result === false) {
713
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
714
+            }
715
+        }
716
+
717
+        $oldEmailAddress = $user->getEMailAddress();
718
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
719
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
720
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
721
+        ) {
722
+            // this is the only permission a backend provides and is also used
723
+            // for the permission of setting a email address
724
+            if (!$user->canChangeDisplayName()) {
725
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
726
+            }
727
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
728
+        }
729
+
730
+        $this->accountManager->updateUser($user, $data);
731
+    }
732
+
733
+    /**
734
+     * Count all unique users visible for the current admin/subadmin.
735
+     *
736
+     * @NoAdminRequired
737
+     *
738
+     * @return DataResponse
739
+     */
740
+    public function stats() {
741
+        $userCount = 0;
742
+        if ($this->isAdmin) {
743
+            $countByBackend = $this->userManager->countUsers();
744
+
745
+            if (!empty($countByBackend)) {
746
+                foreach ($countByBackend as $count) {
747
+                    $userCount += $count;
748
+                }
749
+            }
750
+        } else {
751
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
752
+
753
+            $uniqueUsers = [];
754
+            foreach ($groups as $group) {
755
+                foreach($group->getUsers() as $uid => $displayName) {
756
+                    $uniqueUsers[$uid] = true;
757
+                }
758
+            }
759
+
760
+            $userCount = count($uniqueUsers);
761
+        }
762
+
763
+        return new DataResponse(
764
+            [
765
+                'totalUsers' => $userCount
766
+            ]
767
+        );
768
+    }
769
+
770
+
771
+    /**
772
+     * Set the displayName of a user
773
+     *
774
+     * @NoAdminRequired
775
+     * @NoSubadminRequired
776
+     * @PasswordConfirmationRequired
777
+     * @todo merge into saveUserSettings
778
+     *
779
+     * @param string $username
780
+     * @param string $displayName
781
+     * @return DataResponse
782
+     */
783
+    public function setDisplayName($username, $displayName) {
784
+        $currentUser = $this->userSession->getUser();
785
+        $user = $this->userManager->get($username);
786
+
787
+        if ($user === null ||
788
+            !$user->canChangeDisplayName() ||
789
+            (
790
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
791
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
792
+                $currentUser->getUID() !== $username
793
+
794
+            )
795
+        ) {
796
+            return new DataResponse([
797
+                'status' => 'error',
798
+                'data' => [
799
+                    'message' => $this->l10n->t('Authentication error'),
800
+                ],
801
+            ]);
802
+        }
803
+
804
+        $userData = $this->accountManager->getUser($user);
805
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
806
+
807
+
808
+        try {
809
+            $this->saveUserSettings($user, $userData);
810
+            return new DataResponse([
811
+                'status' => 'success',
812
+                'data' => [
813
+                    'message' => $this->l10n->t('Your full name has been changed.'),
814
+                    'username' => $username,
815
+                    'displayName' => $displayName,
816
+                ],
817
+            ]);
818
+        } catch (ForbiddenException $e) {
819
+            return new DataResponse([
820
+                'status' => 'error',
821
+                'data' => [
822
+                    'message' => $e->getMessage(),
823
+                    'displayName' => $user->getDisplayName(),
824
+                ],
825
+            ]);
826
+        }
827
+    }
828
+
829
+    /**
830
+     * Set the mail address of a user
831
+     *
832
+     * @NoAdminRequired
833
+     * @NoSubadminRequired
834
+     * @PasswordConfirmationRequired
835
+     *
836
+     * @param string $id
837
+     * @param string $mailAddress
838
+     * @return DataResponse
839
+     */
840
+    public function setEMailAddress($id, $mailAddress) {
841
+        $user = $this->userManager->get($id);
842
+        if (!$this->isAdmin
843
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
844
+        ) {
845
+            return new DataResponse(
846
+                array(
847
+                    'status' => 'error',
848
+                    'data' => array(
849
+                        'message' => (string)$this->l10n->t('Forbidden')
850
+                    )
851
+                ),
852
+                Http::STATUS_FORBIDDEN
853
+            );
854
+        }
855
+
856
+        if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
857
+            return new DataResponse(
858
+                array(
859
+                    'status' => 'error',
860
+                    'data' => array(
861
+                        'message' => (string)$this->l10n->t('Invalid mail address')
862
+                    )
863
+                ),
864
+                Http::STATUS_UNPROCESSABLE_ENTITY
865
+            );
866
+        }
867
+
868
+        if (!$user) {
869
+            return new DataResponse(
870
+                array(
871
+                    'status' => 'error',
872
+                    'data' => array(
873
+                        'message' => (string)$this->l10n->t('Invalid user')
874
+                    )
875
+                ),
876
+                Http::STATUS_UNPROCESSABLE_ENTITY
877
+            );
878
+        }
879
+        // this is the only permission a backend provides and is also used
880
+        // for the permission of setting a email address
881
+        if (!$user->canChangeDisplayName()) {
882
+            return new DataResponse(
883
+                array(
884
+                    'status' => 'error',
885
+                    'data' => array(
886
+                        'message' => (string)$this->l10n->t('Unable to change mail address')
887
+                    )
888
+                ),
889
+                Http::STATUS_FORBIDDEN
890
+            );
891
+        }
892
+
893
+        $userData = $this->accountManager->getUser($user);
894
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
895
+
896
+        try {
897
+            $this->saveUserSettings($user, $userData);
898
+            return new DataResponse(
899
+                array(
900
+                    'status' => 'success',
901
+                    'data' => array(
902
+                        'username' => $id,
903
+                        'mailAddress' => $mailAddress,
904
+                        'message' => (string)$this->l10n->t('Email saved')
905
+                    )
906
+                ),
907
+                Http::STATUS_OK
908
+            );
909
+        } catch (ForbiddenException $e) {
910
+            return new DataResponse([
911
+                'status' => 'error',
912
+                'data' => [
913
+                    'message' => $e->getMessage()
914
+                ],
915
+            ]);
916
+        }
917
+    }
918 918
 
919 919
 }
Please login to merge, or discard this patch.