Completed
Pull Request — master (#5342)
by Morris
16:23
created

UsersController::create()   D

Complexity

Conditions 20
Paths 75

Size

Total Lines 116
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 61
nc 75
nop 4
dl 0
loc 116
rs 4.7294
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Clark Tomlinson <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\Settings\Controller;
32
33
use OC\Accounts\AccountManager;
34
use OC\AppFramework\Http;
35
use OC\ForbiddenException;
36
use OC\Settings\Mailer\NewUserMailHelper;
37
use OC\Security\IdentityProof\Manager;
38
use OCP\App\IAppManager;
39
use OCP\AppFramework\Controller;
40
use OCP\AppFramework\Http\DataResponse;
41
use OCP\AppFramework\Utility\ITimeFactory;
42
use OCP\BackgroundJob\IJobList;
43
use OCP\Files\Config\IUserMountCache;
44
use OCP\IConfig;
45
use OCP\IGroupManager;
46
use OCP\IL10N;
47
use OCP\ILogger;
48
use OCP\IRequest;
49
use OCP\IURLGenerator;
50
use OCP\IUser;
51
use OCP\IUserManager;
52
use OCP\IUserSession;
53
use OCP\Mail\IMailer;
54
use OCP\IAvatarManager;
55
use OCP\Security\ICrypto;
56
use OCP\Security\ISecureRandom;
57
use OCP\Util;
58
59
/**
60
 * @package OC\Settings\Controller
61
 */
62
class UsersController extends Controller {
63
	/** @var IL10N */
64
	private $l10n;
65
	/** @var IUserSession */
66
	private $userSession;
67
	/** @var bool */
68
	private $isAdmin;
69
	/** @var IUserManager */
70
	private $userManager;
71
	/** @var IGroupManager */
72
	private $groupManager;
73
	/** @var IConfig */
74
	private $config;
75
	/** @var ILogger */
76
	private $log;
77
	/** @var IMailer */
78
	private $mailer;
79
	/** @var bool contains the state of the encryption app */
80
	private $isEncryptionAppEnabled;
81
	/** @var bool contains the state of the admin recovery setting */
82
	private $isRestoreEnabled = false;
83
	/** @var IAppManager */
84
	private $appManager;
85
	/** @var IAvatarManager */
86
	private $avatarManager;
87
	/** @var AccountManager */
88
	private $accountManager;
89
	/** @var ISecureRandom */
90
	private $secureRandom;
91
	/** @var NewUserMailHelper */
92
	private $newUserMailHelper;
93
	/** @var ITimeFactory */
94
	private $timeFactory;
95
	/** @var ICrypto */
96
	private $crypto;
97
	/** @var Manager */
98
	private $keyManager;
99
	/** @var IJobList */
100
	private $jobList;
101
	/** @var IUserMountCache */
102
	private $userMountCache;
103
104
	/**
105
	 * @param string $appName
106
	 * @param IRequest $request
107
	 * @param IUserManager $userManager
108
	 * @param IGroupManager $groupManager
109
	 * @param IUserSession $userSession
110
	 * @param IConfig $config
111
	 * @param bool $isAdmin
112
	 * @param IL10N $l10n
113
	 * @param ILogger $log
114
	 * @param IMailer $mailer
115
	 * @param IURLGenerator $urlGenerator
116
	 * @param IAppManager $appManager
117
	 * @param IAvatarManager $avatarManager
118
	 * @param AccountManager $accountManager
119
	 * @param ISecureRandom $secureRandom
120
	 * @param NewUserMailHelper $newUserMailHelper
121
	 * @param ITimeFactory $timeFactory
122
	 * @param ICrypto $crypto
123
	 * @param Manager $keyManager
124
	 * @param IJobList $jobList
125
	 * @param IUserMountCache $userMountCache
126
	 */
127
	public function __construct($appName,
128
								IRequest $request,
129
								IUserManager $userManager,
130
								IGroupManager $groupManager,
131
								IUserSession $userSession,
132
								IConfig $config,
133
								$isAdmin,
134
								IL10N $l10n,
135
								ILogger $log,
136
								IMailer $mailer,
137
								IURLGenerator $urlGenerator,
0 ignored issues
show
Unused Code introduced by
The parameter $urlGenerator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
138
								IAppManager $appManager,
139
								IAvatarManager $avatarManager,
140
								AccountManager $accountManager,
141
								ISecureRandom $secureRandom,
142
								NewUserMailHelper $newUserMailHelper,
143
								ITimeFactory $timeFactory,
144
								ICrypto $crypto,
145
								Manager $keyManager,
146
								IJobList $jobList,
147
								IUserMountCache $userMountCache) {
148
		parent::__construct($appName, $request);
149
		$this->userManager = $userManager;
150
		$this->groupManager = $groupManager;
151
		$this->userSession = $userSession;
152
		$this->config = $config;
153
		$this->isAdmin = $isAdmin;
154
		$this->l10n = $l10n;
155
		$this->log = $log;
156
		$this->mailer = $mailer;
157
		$this->appManager = $appManager;
158
		$this->avatarManager = $avatarManager;
159
		$this->accountManager = $accountManager;
160
		$this->secureRandom = $secureRandom;
161
		$this->newUserMailHelper = $newUserMailHelper;
162
		$this->timeFactory = $timeFactory;
163
		$this->crypto = $crypto;
164
		$this->keyManager = $keyManager;
165
		$this->jobList = $jobList;
166
		$this->userMountCache = $userMountCache;
167
168
		// check for encryption state - TODO see formatUserForIndex
169
		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
170
		if ($this->isEncryptionAppEnabled) {
171
			// putting this directly in empty is possible in PHP 5.5+
172
			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
173
			$this->isRestoreEnabled = !empty($result);
174
		}
175
	}
176
177
	/**
178
	 * @param IUser $user
179
	 * @param array $userGroups
180
	 * @return array
181
	 */
182
	private function formatUserForIndex(IUser $user, array $userGroups = null) {
183
184
		// TODO: eliminate this encryption specific code below and somehow
185
		// hook in additional user info from other apps
186
187
		// recovery isn't possible if admin or user has it disabled and encryption
188
		// is enabled - so we eliminate the else paths in the conditional tree
189
		// below
190
		$restorePossible = false;
191
192
		if ($this->isEncryptionAppEnabled) {
193
			if ($this->isRestoreEnabled) {
194
				// check for the users recovery setting
195
				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
196
				// method call inside empty is possible with PHP 5.5+
197
				$recoveryModeEnabled = !empty($recoveryMode);
198
				if ($recoveryModeEnabled) {
199
					// user also has recovery mode enabled
200
					$restorePossible = true;
201
				}
202
			}
203
		} else {
204
			// recovery is possible if encryption is disabled (plain files are
205
			// available)
206
			$restorePossible = true;
207
		}
208
209
		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
210
		foreach ($subAdminGroups as $key => $subAdminGroup) {
211
			$subAdminGroups[$key] = $subAdminGroup->getGID();
212
		}
213
214
		$displayName = $user->getEMailAddress();
215
		if (is_null($displayName)) {
216
			$displayName = '';
217
		}
218
219
		$avatarAvailable = false;
220
		try {
221
			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
222
		} catch (\Exception $e) {
223
			//No avatar yet
224
		}
225
226
		return [
227
			'name' => $user->getUID(),
228
			'displayname' => $user->getDisplayName(),
229
			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
230
			'subadmin' => $subAdminGroups,
231
			'quota' => $user->getQuota(),
232
			'quota_bytes' => Util::computerFileSize($user->getQuota()),
233
			'storageLocation' => $user->getHome(),
234
			'lastLogin' => $user->getLastLogin() * 1000,
235
			'backend' => $user->getBackendClassName(),
236
			'email' => $displayName,
237
			'isRestoreDisabled' => !$restorePossible,
238
			'isAvatarAvailable' => $avatarAvailable,
239
			'isEnabled' => $user->isEnabled(),
240
		];
241
	}
242
243
	/**
244
	 * @param array $userIDs Array with schema [$uid => $displayName]
245
	 * @return IUser[]
246
	 */
247
	private function getUsersForUID(array $userIDs) {
248
		$users = [];
249
		foreach ($userIDs as $uid => $displayName) {
250
			$users[$uid] = $this->userManager->get($uid);
251
		}
252
		return $users;
253
	}
254
255
	/**
256
	 * @NoAdminRequired
257
	 *
258
	 * @param int $offset
259
	 * @param int $limit
260
	 * @param string $gid GID to filter for
261
	 * @param string $pattern Pattern to search for in the username
262
	 * @param string $backend Backend to filter for (class-name)
263
	 * @return DataResponse
264
	 *
265
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
266
	 */
267
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
268
		// Remove backends
269
		if (!empty($backend)) {
270
			$activeBackends = $this->userManager->getBackends();
271
			$this->userManager->clearBackends();
272
			foreach ($activeBackends as $singleActiveBackend) {
273
				if ($backend === get_class($singleActiveBackend)) {
274
					$this->userManager->registerBackend($singleActiveBackend);
275
					break;
276
				}
277
			}
278
		}
279
280
		$userObjects = [];
281
		$users = [];
282
		if ($this->isAdmin) {
283
			if ($gid !== '' && $gid !== '_disabledUsers') {
284
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
285
			} else {
286
				$batch = $this->userManager->search($pattern, $limit, $offset);
287
			}
288
289
			foreach ($batch as $user) {
290 View Code Duplication
				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
291
					($gid === '_disabledUsers' && !$user->isEnabled())
292
				) {
293
					$userObjects[] = $user;
294
					$users[] = $this->formatUserForIndex($user);
295
				}
296
			}
297
298
		} else {
299
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
300
			// New class returns IGroup[] so convert back
301
			$gids = [];
302
			foreach ($subAdminOfGroups as $group) {
303
				$gids[] = $group->getGID();
304
			}
305
			$subAdminOfGroups = $gids;
306
307
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
308
			if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
309
				$gid = '';
310
			}
311
312
			// Batch all groups the user is subadmin of when a group is specified
313
			$batch = [];
314
			if ($gid === '') {
315
				foreach ($subAdminOfGroups as $group) {
316
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
317
318
					foreach ($groupUsers as $uid => $displayName) {
319
						$batch[$uid] = $displayName;
320
					}
321
				}
322
			} else {
323
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
324
			}
325
			$batch = $this->getUsersForUID($batch);
326
327
			foreach ($batch as $user) {
328
				// Only add the groups, this user is a subadmin of
329
				$userGroups = array_values(array_intersect(
330
					$this->groupManager->getUserGroupIds($user),
331
					$subAdminOfGroups
332
				));
333 View Code Duplication
				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
334
					($gid === '_disabledUsers' && !$user->isEnabled())
335
				) {
336
					$userObjects[] = $user;
337
					$users[] = $this->formatUserForIndex($user, $userGroups);
338
				}
339
			}
340
		}
341
342
		$usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
343
344
		foreach ($users as &$userData) {
345
			$userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
346
		}
347
348
		return new DataResponse($users);
349
	}
350
351
	/**
352
	 * @NoAdminRequired
353
	 * @PasswordConfirmationRequired
354
	 *
355
	 * @param string $username
356
	 * @param string $password
357
	 * @param array $groups
358
	 * @param string $email
359
	 * @return DataResponse
360
	 */
361
	public function create($username, $password, array $groups = [], $email = '') {
362
		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
363
			return new DataResponse(
364
				[
365
					'message' => (string)$this->l10n->t('Invalid mail address')
366
				],
367
				Http::STATUS_UNPROCESSABLE_ENTITY
368
			);
369
		}
370
371
		$currentUser = $this->userSession->getUser();
372
373
		if (!$this->isAdmin) {
374
			if (!empty($groups)) {
375
				foreach ($groups as $key => $group) {
376
					$groupObject = $this->groupManager->get($group);
377
					if ($groupObject === null) {
378
						unset($groups[$key]);
379
						continue;
380
					}
381
382
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
383
						unset($groups[$key]);
384
					}
385
				}
386
			}
387
388
			if (empty($groups)) {
389
				return new DataResponse(
390
					[
391
						'message' => $this->l10n->t('No valid group selected'),
392
					],
393
					Http::STATUS_FORBIDDEN
394
				);
395
			}
396
		}
397
398
		if ($this->userManager->userExists($username)) {
399
			return new DataResponse(
400
				[
401
					'message' => (string)$this->l10n->t('A user with that name already exists.')
402
				],
403
				Http::STATUS_CONFLICT
404
			);
405
		}
406
407
		$generatePasswordResetToken = false;
408
		if ($password === '') {
409
			if ($email === '') {
410
				return new DataResponse(
411
					[
412
						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
413
					],
414
					Http::STATUS_UNPROCESSABLE_ENTITY
415
				);
416
			}
417
418
			$password = $this->secureRandom->generate(32);
419
			$generatePasswordResetToken = true;
420
		}
421
422
		try {
423
			$user = $this->userManager->createUser($username, $password);
424
		} catch (\Exception $exception) {
425
			$message = $exception->getMessage();
426
			if (!$message) {
427
				$message = $this->l10n->t('Unable to create user.');
428
			}
429
			return new DataResponse(
430
				[
431
					'message' => (string)$message,
432
				],
433
				Http::STATUS_FORBIDDEN
434
			);
435
		}
436
437
		if ($user instanceof IUser) {
438
			if ($groups !== null) {
439
				foreach ($groups as $groupName) {
440
					$group = $this->groupManager->get($groupName);
441
442
					if (empty($group)) {
443
						$group = $this->groupManager->createGroup($groupName);
444
					}
445
					$group->addUser($user);
446
				}
447
			}
448
			/**
449
			 * Send new user mail only if a mail is set
450
			 */
451
			if ($email !== '') {
452
				$user->setEMailAddress($email);
453
				try {
454
					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
455
					$this->newUserMailHelper->sendMail($user, $emailTemplate);
456
				} catch (\Exception $e) {
457
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
458
				}
459
			}
460
			// fetch users groups
461
			$userGroups = $this->groupManager->getUserGroupIds($user);
462
463
			return new DataResponse(
464
				$this->formatUserForIndex($user, $userGroups),
465
				Http::STATUS_CREATED
466
			);
467
		}
468
469
		return new DataResponse(
470
			[
471
				'message' => (string)$this->l10n->t('Unable to create user.')
472
			],
473
			Http::STATUS_FORBIDDEN
474
		);
475
476
	}
477
478
	/**
479
	 * @NoAdminRequired
480
	 * @PasswordConfirmationRequired
481
	 *
482
	 * @param string $id
483
	 * @return DataResponse
484
	 */
485
	public function destroy($id) {
486
		$userId = $this->userSession->getUser()->getUID();
487
		$user = $this->userManager->get($id);
488
489
		if ($userId === $id) {
490
			return new DataResponse(
491
				[
492
					'status' => 'error',
493
					'data' => [
494
						'message' => (string)$this->l10n->t('Unable to delete user.')
495
					]
496
				],
497
				Http::STATUS_FORBIDDEN
498
			);
499
		}
500
501 View Code Duplication
		if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
502
			return new DataResponse(
503
				[
504
					'status' => 'error',
505
					'data' => [
506
						'message' => (string)$this->l10n->t('Authentication error')
507
					]
508
				],
509
				Http::STATUS_FORBIDDEN
510
			);
511
		}
512
513
		if ($user) {
514
			if ($user->delete()) {
515
				return new DataResponse(
516
					[
517
						'status' => 'success',
518
						'data' => [
519
							'username' => $id
520
						]
521
					],
522
					Http::STATUS_NO_CONTENT
523
				);
524
			}
525
		}
526
527
		return new DataResponse(
528
			[
529
				'status' => 'error',
530
				'data' => [
531
					'message' => (string)$this->l10n->t('Unable to delete user.')
532
				]
533
			],
534
			Http::STATUS_FORBIDDEN
535
		);
536
	}
537
538
	/**
539
	 * @NoAdminRequired
540
	 *
541
	 * @param string $id
542
	 * @param int $enabled
543
	 * @return DataResponse
544
	 */
545
	public function setEnabled($id, $enabled) {
546
		$enabled = (bool)$enabled;
547
		if ($enabled) {
548
			$errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
549
		} else {
550
			$errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
551
		}
552
553
		$userId = $this->userSession->getUser()->getUID();
554
		$user = $this->userManager->get($id);
555
556 View Code Duplication
		if ($userId === $id) {
557
			return new DataResponse(
558
				[
559
					'status' => 'error',
560
					'data' => [
561
						'message' => $errorMsgGeneral
562
					]
563
				], Http::STATUS_FORBIDDEN
564
			);
565
		}
566
567
		if ($user) {
568 View Code Duplication
			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
569
				return new DataResponse(
570
					[
571
						'status' => 'error',
572
						'data' => [
573
							'message' => (string)$this->l10n->t('Authentication error')
574
						]
575
					],
576
					Http::STATUS_FORBIDDEN
577
				);
578
			}
579
580
			$user->setEnabled($enabled);
581
			return new DataResponse(
582
				[
583
					'status' => 'success',
584
					'data' => [
585
						'username' => $id,
586
						'enabled' => $enabled
587
					]
588
				]
589
			);
590 View Code Duplication
		} else {
591
			return new DataResponse(
592
				[
593
					'status' => 'error',
594
					'data' => [
595
						'message' => $errorMsgGeneral
596
					]
597
				],
598
				Http::STATUS_FORBIDDEN
599
			);
600
		}
601
602
	}
603
604
	/**
605
	 * Set the mail address of a user
606
	 *
607
	 * @NoAdminRequired
608
	 * @NoSubadminRequired
609
	 * @PasswordConfirmationRequired
610
	 *
611
	 * @param string $account
612
	 * @param bool $onlyVerificationCode only return verification code without updating the data
613
	 * @return DataResponse
614
	 */
615
	public function getVerificationCode($account, $onlyVerificationCode) {
616
617
		$user = $this->userSession->getUser();
618
619
		if ($user === null) {
620
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
621
		}
622
623
		$accountData = $this->accountManager->getUser($user);
624
		$cloudId = $user->getCloudId();
625
		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
626
		$signature = $this->signMessage($user, $message);
627
628
		$code = $message . ' ' . $signature;
629
		$codeMd5 = $message . ' ' . md5($signature);
630
631
		switch ($account) {
632 View Code Duplication
			case 'verify-twitter':
633
				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
634
				$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):');
635
				$code = $codeMd5;
636
				$type = AccountManager::PROPERTY_TWITTER;
637
				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
638
				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
639
				break;
640 View Code Duplication
			case 'verify-website':
641
				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
642
				$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):');
643
				$type = AccountManager::PROPERTY_WEBSITE;
644
				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
645
				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
646
				break;
647
			default:
648
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
649
		}
650
651
		if ($onlyVerificationCode === false) {
652
			$this->accountManager->updateUser($user, $accountData);
653
654
			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
655
				[
656
					'verificationCode' => $code,
657
					'data' => $data,
658
					'type' => $type,
659
					'uid' => $user->getUID(),
660
					'try' => 0,
661
					'lastRun' => $this->getCurrentTime()
662
				]
663
			);
664
		}
665
666
		return new DataResponse(['msg' => $msg, 'code' => $code]);
667
	}
668
669
	/**
670
	 * get current timestamp
671
	 *
672
	 * @return int
673
	 */
674
	protected function getCurrentTime() {
675
		return time();
676
	}
677
678
	/**
679
	 * sign message with users private key
680
	 *
681
	 * @param IUser $user
682
	 * @param string $message
683
	 *
684
	 * @return string base64 encoded signature
685
	 */
686
	protected function signMessage(IUser $user, $message) {
687
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
688
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
689
		$signatureBase64 = base64_encode($signature);
690
691
		return $signatureBase64;
692
	}
693
694
	/**
695
	 * @NoAdminRequired
696
	 * @NoSubadminRequired
697
	 * @PasswordConfirmationRequired
698
	 *
699
	 * @param string $avatarScope
700
	 * @param string $displayname
701
	 * @param string $displaynameScope
702
	 * @param string $phone
703
	 * @param string $phoneScope
704
	 * @param string $email
705
	 * @param string $emailScope
706
	 * @param string $website
707
	 * @param string $websiteScope
708
	 * @param string $address
709
	 * @param string $addressScope
710
	 * @param string $twitter
711
	 * @param string $twitterScope
712
	 * @return DataResponse
713
	 */
714
	public function setUserSettings($avatarScope,
715
									$displayname,
716
									$displaynameScope,
717
									$phone,
718
									$phoneScope,
719
									$email,
720
									$emailScope,
721
									$website,
722
									$websiteScope,
723
									$address,
724
									$addressScope,
725
									$twitter,
726
									$twitterScope
727
	) {
728
729
		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
730
			return new DataResponse(
731
				[
732
					'status' => 'error',
733
					'data' => [
734
						'message' => (string)$this->l10n->t('Invalid mail address')
735
					]
736
				],
737
				Http::STATUS_UNPROCESSABLE_ENTITY
738
			);
739
		}
740
741
		$user = $this->userSession->getUser();
742
743
		$data = $this->accountManager->getUser($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 741 can be null; however, OC\Accounts\AccountManager::getUser() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
744
745
		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
746
		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
747
			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
748
			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
749
		}
750
751
		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
752
			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
753
			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
754
			if ($shareProvider->isLookupServerUploadEnabled()) {
755
				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
756
				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
757
				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
758
				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
759
			}
760
		}
761
762
		try {
763
			$this->saveUserSettings($user, $data);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 741 can be null; however, OC\Settings\Controller\U...ler::saveUserSettings() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
764
			return new DataResponse(
765
				[
766
					'status' => 'success',
767
					'data' => [
768
						'userId' => $user->getUID(),
769
						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
770
						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
771
						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
772
						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
773
						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
774
						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
775
						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
776
						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
777
						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
778
						'message' => (string)$this->l10n->t('Settings saved')
779
					]
780
				],
781
				Http::STATUS_OK
782
			);
783
		} catch (ForbiddenException $e) {
784
			return new DataResponse([
785
				'status' => 'error',
786
				'data' => [
787
					'message' => $e->getMessage()
788
				],
789
			]);
790
		}
791
792
	}
793
794
795
	/**
796
	 * update account manager with new user data
797
	 *
798
	 * @param IUser $user
799
	 * @param array $data
800
	 * @throws ForbiddenException
801
	 */
802
	protected function saveUserSettings(IUser $user, $data) {
803
804
		// keep the user back-end up-to-date with the latest display name and email
805
		// address
806
		$oldDisplayName = $user->getDisplayName();
807
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
808 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
809
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
810
		) {
811
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
812
			if ($result === false) {
813
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
814
			}
815
		}
816
817
		$oldEmailAddress = $user->getEMailAddress();
818
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
819 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
820
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
821
		) {
822
			// this is the only permission a backend provides and is also used
823
			// for the permission of setting a email address
824
			if (!$user->canChangeDisplayName()) {
825
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
826
			}
827
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
828
		}
829
830
		$this->accountManager->updateUser($user, $data);
831
	}
832
833
	/**
834
	 * Count all unique users visible for the current admin/subadmin.
835
	 *
836
	 * @NoAdminRequired
837
	 *
838
	 * @return DataResponse
839
	 */
840
	public function stats() {
841
		$userCount = 0;
842
		if ($this->isAdmin) {
843
			$countByBackend = $this->userManager->countUsers();
844
845
			if (!empty($countByBackend)) {
846
				foreach ($countByBackend as $count) {
847
					$userCount += $count;
848
				}
849
			}
850
		} else {
851
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
852
853
			$uniqueUsers = [];
854
			foreach ($groups as $group) {
855
				foreach ($group->getUsers() as $uid => $displayName) {
856
					$uniqueUsers[$uid] = true;
857
				}
858
			}
859
860
			$userCount = count($uniqueUsers);
861
		}
862
863
		return new DataResponse(
864
			[
865
				'totalUsers' => $userCount
866
			]
867
		);
868
	}
869
870
871
	/**
872
	 * Set the displayName of a user
873
	 *
874
	 * @NoAdminRequired
875
	 * @NoSubadminRequired
876
	 * @PasswordConfirmationRequired
877
	 * @todo merge into saveUserSettings
878
	 *
879
	 * @param string $username
880
	 * @param string $displayName
881
	 * @return DataResponse
882
	 */
883
	public function setDisplayName($username, $displayName) {
884
		$currentUser = $this->userSession->getUser();
885
		$user = $this->userManager->get($username);
886
887
		if ($user === null ||
888
			!$user->canChangeDisplayName() ||
889
			(
890
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
891
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
892
				$currentUser->getUID() !== $username
893
894
			)
895
		) {
896
			return new DataResponse([
897
				'status' => 'error',
898
				'data' => [
899
					'message' => $this->l10n->t('Authentication error'),
900
				],
901
			]);
902
		}
903
904
		$userData = $this->accountManager->getUser($user);
905
		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
906
907
908
		try {
909
			$this->saveUserSettings($user, $userData);
910
			return new DataResponse([
911
				'status' => 'success',
912
				'data' => [
913
					'message' => $this->l10n->t('Your full name has been changed.'),
914
					'username' => $username,
915
					'displayName' => $displayName,
916
				],
917
			]);
918
		} catch (ForbiddenException $e) {
919
			return new DataResponse([
920
				'status' => 'error',
921
				'data' => [
922
					'message' => $e->getMessage(),
923
					'displayName' => $user->getDisplayName(),
924
				],
925
			]);
926
		}
927
	}
928
929
	/**
930
	 * Set the mail address of a user
931
	 *
932
	 * @NoAdminRequired
933
	 * @NoSubadminRequired
934
	 * @PasswordConfirmationRequired
935
	 *
936
	 * @param string $id
937
	 * @param string $mailAddress
938
	 * @return DataResponse
939
	 */
940
	public function setEMailAddress($id, $mailAddress) {
941
		$user = $this->userManager->get($id);
942
		if (!$this->isAdmin
943
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
944
		) {
945
			return new DataResponse(
946
				[
947
					'status' => 'error',
948
					'data' => [
949
						'message' => (string)$this->l10n->t('Forbidden')
950
					]
951
				],
952
				Http::STATUS_FORBIDDEN
953
			);
954
		}
955
956
		if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
957
			return new DataResponse(
958
				[
959
					'status' => 'error',
960
					'data' => [
961
						'message' => (string)$this->l10n->t('Invalid mail address')
962
					]
963
				],
964
				Http::STATUS_UNPROCESSABLE_ENTITY
965
			);
966
		}
967
968
		if (!$user) {
969
			return new DataResponse(
970
				[
971
					'status' => 'error',
972
					'data' => [
973
						'message' => (string)$this->l10n->t('Invalid user')
974
					]
975
				],
976
				Http::STATUS_UNPROCESSABLE_ENTITY
977
			);
978
		}
979
		// this is the only permission a backend provides and is also used
980
		// for the permission of setting a email address
981
		if (!$user->canChangeDisplayName()) {
982
			return new DataResponse(
983
				[
984
					'status' => 'error',
985
					'data' => [
986
						'message' => (string)$this->l10n->t('Unable to change mail address')
987
					]
988
				],
989
				Http::STATUS_FORBIDDEN
990
			);
991
		}
992
993
		$userData = $this->accountManager->getUser($user);
994
		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
995
996
		try {
997
			$this->saveUserSettings($user, $userData);
998
			return new DataResponse(
999
				[
1000
					'status' => 'success',
1001
					'data' => [
1002
						'username' => $id,
1003
						'mailAddress' => $mailAddress,
1004
						'message' => (string)$this->l10n->t('Email saved')
1005
					]
1006
				],
1007
				Http::STATUS_OK
1008
			);
1009
		} catch (ForbiddenException $e) {
1010
			return new DataResponse([
1011
				'status' => 'error',
1012
				'data' => [
1013
					'message' => $e->getMessage()
1014
				],
1015
			]);
1016
		}
1017
	}
1018
1019
}
1020