Completed
Push — master ( 85fefc...4fcdbb )
by Thomas
09:37
created

UsersController::isAdmin()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 9
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Clark Tomlinson <[email protected]>
5
 * @author Joas Schilling <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 * @author Ujjwal Bhardwaj <[email protected]>
12
 * @author Vincent Petry <[email protected]>
13
 *
14
 * @copyright Copyright (c) 2017, ownCloud GmbH
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\AppFramework\Http;
34
use OC\User\User;
35
use OCP\App\IAppManager;
36
use OCP\AppFramework\Controller;
37
use OCP\AppFramework\Http\DataResponse;
38
use OCP\AppFramework\Http\JSONResponse;
39
use OCP\AppFramework\Http\RedirectResponse;
40
use OCP\AppFramework\Http\TemplateResponse;
41
use OCP\AppFramework\Utility\ITimeFactory;
42
use OCP\IConfig;
43
use OCP\IGroupManager;
44
use OCP\IL10N;
45
use OCP\ILogger;
46
use OCP\IRequest;
47
use OCP\IURLGenerator;
48
use OCP\IUser;
49
use OCP\IUserManager;
50
use OCP\IUserSession;
51
use OCP\Mail\IMailer;
52
use OCP\IAvatarManager;
53
use OCP\Security\ISecureRandom;
54
55
/**
56
 * @package OC\Settings\Controller
57
 */
58
class UsersController extends Controller {
59
	/** @var IL10N */
60
	private $l10n;
61
	/** @var IUserSession */
62
	private $userSession;
63
	/** @var bool */
64
	private $isAdmin;
65
	/** @var IUserManager */
66
	private $userManager;
67
	/** @var IGroupManager */
68
	private $groupManager;
69
	/** @var IConfig */
70
	private $config;
71
	/** @var ILogger */
72
	private $log;
73
	/** @var \OC_Defaults */
74
	private $defaults;
75
	/** @var IMailer */
76
	private $mailer;
77
	/** @var string */
78
	private $fromMailAddress;
79
	/** @var IURLGenerator */
80
	private $urlGenerator;
81
	/** @var bool contains the state of the encryption app */
82
	private $isEncryptionAppEnabled;
83
	/** @var bool contains the state of the admin recovery setting */
84
	private $isRestoreEnabled = false;
85
	/** @var IAvatarManager */
86
	private $avatarManager;
87
	/** @var ISecureRandom */
88
	protected $secureRandom;
89
	/** @var ITimeFactory */
90
	protected $timeFactory;
91
92
	/**
93
	 * @param string $appName
94
	 * @param IRequest $request
95
	 * @param IUserManager $userManager
96
	 * @param IGroupManager $groupManager
97
	 * @param IUserSession $userSession
98
	 * @param IConfig $config
99
	 * @param ISecureRandom $secureRandom
100
	 * @param IL10N $l10n
101
	 * @param ILogger $log
102
	 * @param \OC_Defaults $defaults
103
	 * @param IMailer $mailer
104
	 * @param ITimeFactory $timeFactory
105
	 * @param $fromMailAddress
106
	 * @param IURLGenerator $urlGenerator
107
	 * @param IAppManager $appManager
108
	 * @param IAvatarManager $avatarManager
109
	 */
110
	public function __construct($appName,
111
								IRequest $request,
112
								IUserManager $userManager,
113
								IGroupManager $groupManager,
114
								IUserSession $userSession,
115
								IConfig $config,
116
								ISecureRandom $secureRandom,
117
								IL10N $l10n,
118
								ILogger $log,
119
								\OC_Defaults $defaults,
120
								IMailer $mailer,
121
								ITimeFactory $timeFactory,
122
								$fromMailAddress,
123
								IURLGenerator $urlGenerator,
124
								IAppManager $appManager,
125
								IAvatarManager $avatarManager) {
126
		parent::__construct($appName, $request);
127
		$this->userManager = $userManager;
128
		$this->groupManager = $groupManager;
129
		$this->userSession = $userSession;
130
		$this->config = $config;
131
		$this->l10n = $l10n;
132
		$this->secureRandom = $secureRandom;
133
		$this->log = $log;
134
		$this->defaults = $defaults;
135
		$this->mailer = $mailer;
136
		$this->timeFactory = $timeFactory;
137
		$this->fromMailAddress = $fromMailAddress;
138
		$this->urlGenerator = $urlGenerator;
139
		$this->avatarManager = $avatarManager;
140
		$this->isAdmin = $this->isAdmin();
141
142
		// check for encryption state - TODO see formatUserForIndex
143
		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
144
		if($this->isEncryptionAppEnabled) {
145
			// putting this directly in empty is possible in PHP 5.5+
146
			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
147
			$this->isRestoreEnabled = !empty($result);
148
		}
149
	}
150
151
	/**
152
	 * @param IUser $user
153
	 * @param array $userGroups
154
	 * @return array
155
	 */
156
	private function formatUserForIndex(IUser $user, array $userGroups = null) {
157
158
		// TODO: eliminate this encryption specific code below and somehow
159
		// hook in additional user info from other apps
160
161
		// recovery isn't possible if admin or user has it disabled and encryption
162
		// is enabled - so we eliminate the else paths in the conditional tree
163
		// below
164
		$restorePossible = false;
165
166
		if ($this->isEncryptionAppEnabled) {
167
			if ($this->isRestoreEnabled) {
168
				// check for the users recovery setting
169
				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
170
				// method call inside empty is possible with PHP 5.5+
171
				$recoveryModeEnabled = !empty($recoveryMode);
172
				if ($recoveryModeEnabled) {
173
					// user also has recovery mode enabled
174
					$restorePossible = true;
175
				}
176
			}
177
		} else {
178
			// recovery is possible if encryption is disabled (plain files are
179
			// available)
180
			$restorePossible = true;
181
		}
182
183
		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
184
		foreach($subAdminGroups as $key => $subAdminGroup) {
185
			$subAdminGroups[$key] = $subAdminGroup->getGID();
186
		}
187
188
		$displayName = $user->getEMailAddress();
189
		if (is_null($displayName)) {
190
			$displayName = '';
191
		}
192
193
		$avatarAvailable = false;
194
		if ($this->config->getSystemValue('enable_avatars', true) === true) {
195
			try {
196
				$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
197
			} catch (\Exception $e) {
198
				//No avatar yet
199
			}
200
		}
201
202
		return [
203
			'name' => $user->getUID(),
204
			'displayname' => $user->getDisplayName(),
205
			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user, 'management') : $userGroups,
206
			'subadmin' => $subAdminGroups,
207
			'isEnabled' => $user->isEnabled(),
208
			'quota' => $user->getQuota(),
209
			'storageLocation' => $user->getHome(),
210
			'lastLogin' => $user->getLastLogin() * 1000,
211
			'backend' => $user->getBackendClassName(),
212
			'email' => $displayName,
213
			'isRestoreDisabled' => !$restorePossible,
214
			'isAvatarAvailable' => $avatarAvailable,
215
		];
216
	}
217
218
	/**
219
	 * @param array $userIDs Array with schema [$uid => $displayName]
220
	 * @return IUser[]
221
	 */
222
	private function getUsersForUID(array $userIDs) {
223
		$users = [];
224
		foreach ($userIDs as $uid => $displayName) {
225
			$users[$uid] = $this->userManager->get($uid);
226
		}
227
		return $users;
228
	}
229
230
	/**
231
	 * @param string $token
232
	 * @param string $userId
233
	 * @throws \Exception
234
	 */
235
	private function checkEmailChangeToken($token, $userId) {
236
		$user = $this->userManager->get($userId);
237
238
		if ($user === null) {
239
			throw new \Exception($this->l10n->t('Couldn\'t change the email address because the user does not exist'));
240
		}
241
242
		$splittedToken = explode(':', $this->config->getUserValue($userId, 'owncloud', 'changeMail', null));
243 View Code Duplication
		if(count($splittedToken) !== 3) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
244
			$this->config->deleteUserValue($userId, 'owncloud', 'changeMail');
245
			throw new \Exception($this->l10n->t('Couldn\'t change the email address because the token is invalid'));
246
		}
247
248 View Code Duplication
		if ($splittedToken[0] < ($this->timeFactory->getTime() - 60*60*12)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
249
			$this->config->deleteUserValue($userId, 'owncloud', 'changeMail');
250
			throw new \Exception($this->l10n->t('Couldn\'t change the email address because the token is invalid'));
251
		}
252
253 View Code Duplication
		if (!hash_equals($splittedToken[1], $token)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
254
			$this->config->deleteUserValue($userId, 'owncloud', 'changeMail');
255
			throw new \Exception($this->l10n->t('Couldn\'t change the email address because the token is invalid'));
256
		}
257
	}
258
259
	/**
260
	 * @NoAdminRequired
261
	 *
262
	 * @param int $offset
263
	 * @param int $limit
264
	 * @param string $gid GID to filter for
265
	 * @param string $pattern Pattern to find in the account table (userid, displayname, email, additional search terms)
266
	 * @param string $backend Backend to filter for (class-name)
267
	 * @return DataResponse
268
	 *
269
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
270
	 */
271
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
272
		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
273
		if($gid === '_everyone') {
274
			$gid = '';
275
		}
276
277
		// Remove backends
278
		if(!empty($backend)) {
279
			$activeBackends = $this->userManager->getBackends();
280
			$this->userManager->clearBackends();
281
			foreach($activeBackends as $singleActiveBackend) {
282
				if($backend === get_class($singleActiveBackend)) {
283
					$this->userManager->registerBackend($singleActiveBackend);
284
					break;
285
				}
286
			}
287
		}
288
289
		$users = [];
290
		if ($this->isAdmin) {
291
292
			if($gid !== '') {
293
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
294
			} else {
295
				$batch = $this->userManager->find($pattern, $limit, $offset);
296
			}
297
298
			foreach ($batch as $user) {
299
				$users[] = $this->formatUserForIndex($user);
300
			}
301
302
		} else {
303
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, getSubAdminsGroups() 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...
304
			// New class returns IGroup[] so convert back
305
			$gids = [];
306
			foreach ($subAdminOfGroups as $group) {
307
				$gids[] = $group->getGID();
308
			}
309
			$subAdminOfGroups = $gids;
310
311
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
312
			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
313
				$gid = '';
314
			}
315
316
			// Batch all groups the user is subadmin of when a group is specified
317
			$batch = [];
318
			if($gid === '') {
319
				foreach($subAdminOfGroups as $group) {
320
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
321
322
					foreach($groupUsers as $uid => $displayName) {
323
						$batch[$uid] = $displayName;
324
					}
325
				}
326
			} else {
327
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
328
			}
329
			$batch = $this->getUsersForUID($batch);
330
331
			foreach ($batch as $user) {
332
				// Only add the groups, this user is a subadmin of
333
				$userGroups = array_values(array_intersect(
334
					$this->groupManager->getUserGroupIds($user),
335
					$subAdminOfGroups
336
				));
337
				$users[] = $this->formatUserForIndex($user, $userGroups);
338
			}
339
		}
340
341
		return new DataResponse($users);
342
	}
343
344
	/**
345
	 * @NoAdminRequired
346
	 *
347
	 * @param string $username
348
	 * @param string $password
349
	 * @param array $groups
350
	 * @param string $email
351
	 * @return DataResponse
352
	 */
353
	public function create($username, $password, array $groups= [], $email='') {
354
		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
355
			return new DataResponse(
356
				[
357
					'message' => (string)$this->l10n->t('Invalid mail address')
358
				],
359
				Http::STATUS_UNPROCESSABLE_ENTITY
360
			);
361
		}
362
363
		$currentUser = $this->userSession->getUser();
364
365
		if (!$this->isAdmin) {
366
			if (!empty($groups)) {
367
				foreach ($groups as $key => $group) {
368
					$groupObject = $this->groupManager->get($group);
369
					if($groupObject === null) {
370
						unset($groups[$key]);
371
						continue;
372
					}
373
374
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
0 ignored issues
show
Bug introduced by
It seems like $currentUser defined by $this->userSession->getUser() on line 363 can be null; however, OCP\ISubAdminManager::isSubAdminofGroup() 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...
375
						unset($groups[$key]);
376
					}
377
				}
378
			}
379
380
			if (empty($groups)) {
381
				$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($currentUser);
0 ignored issues
show
Bug introduced by
It seems like $currentUser defined by $this->userSession->getUser() on line 363 can be null; however, OCP\ISubAdminManager::getSubAdminsGroups() 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...
382
				// New class returns IGroup[] so convert back
383
				$gids = [];
384
				foreach ($groups as $group) {
385
					$gids[] = $group->getGID();
386
				}
387
				$groups = $gids;
388
			}
389
		}
390
391
		if ($this->userManager->userExists($username)) {
392
			return new DataResponse(
393
				[
394
					'message' => (string)$this->l10n->t('A user with that name already exists.')
395
				],
396
				Http::STATUS_CONFLICT
397
			);
398
		}
399
400
		try {
401
			$user = $this->userManager->createUser($username, $password);
402
		} catch (\Exception $exception) {
403
			$message = $exception->getMessage();
404
			if (!$message) {
405
				$message = $this->l10n->t('Unable to create user.');
406
			}
407
			return new DataResponse(
408
				[
409
					'message' => (string) $message,
410
				],
411
				Http::STATUS_FORBIDDEN
412
			);
413
		}
414
415
		if($user instanceof User) {
416
			if($groups !== null) {
417
				foreach($groups as $groupName) {
418
					$group = $this->groupManager->get($groupName);
419
420
					if(empty($group)) {
421
						$group = $this->groupManager->createGroup($groupName);
422
					}
423
					$group->addUser($user);
424
				}
425
			}
426
			/**
427
			 * Send new user mail only if a mail is set
428
			 */
429
			if($email !== '') {
430
				$user->setEMailAddress($email);
431
432
				// data for the mail template
433
				$mailData = [
434
					'username' => $username,
435
					'url' => $this->urlGenerator->getAbsoluteURL('/')
436
				];
437
438
				$mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
439
				$mailContent = $mail->render();
440
441
				$mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
442
				$plainTextMailContent = $mail->render();
443
444
				$subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
445
446
				try {
447
					$message = $this->mailer->createMessage();
448
					$message->setTo([$email => $username]);
449
					$message->setSubject($subject);
450
					$message->setHtmlBody($mailContent);
0 ignored issues
show
Bug introduced by
It seems like $mailContent defined by $mail->render() on line 439 can also be of type boolean; however, OC\Mail\Message::setHtmlBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
451
					$message->setPlainBody($plainTextMailContent);
0 ignored issues
show
Bug introduced by
It seems like $plainTextMailContent defined by $mail->render() on line 442 can also be of type boolean; however, OC\Mail\Message::setPlainBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
452
					$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
453
					$this->mailer->send($message);
454
				} catch(\Exception $e) {
455
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
456
				}
457
			}
458
			// fetch users groups
459
			$userGroups = $this->groupManager->getUserGroupIds($user);
460
461
			return new DataResponse(
462
				$this->formatUserForIndex($user, $userGroups),
463
				Http::STATUS_CREATED
464
			);
465
		}
466
467
		return new DataResponse(
468
			[
469
				'message' => (string)$this->l10n->t('Unable to create user.')
470
			],
471
			Http::STATUS_FORBIDDEN
472
		);
473
474
	}
475
476
	/**
477
	 * @NoAdminRequired
478
	 *
479
	 * @param string $id
480
	 * @return DataResponse
481
	 */
482
	public function destroy($id) {
483
		$userId = $this->userSession->getUser()->getUID();
484
		$user = $this->userManager->get($id);
485
486 View Code Duplication
		if($userId === $id) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
487
			return new DataResponse(
488
				[
489
					'status' => 'error',
490
					'data' => [
491
						'message' => (string)$this->l10n->t('Unable to delete user.')
492
					]
493
				],
494
				Http::STATUS_FORBIDDEN
495
			);
496
		}
497
498 View Code Duplication
		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, isUserAccessible() 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...
Bug introduced by
It seems like $user defined by $this->userManager->get($id) on line 484 can be null; however, OCP\ISubAdminManager::isUserAccessible() 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...
499
			return new DataResponse(
500
				[
501
					'status' => 'error',
502
					'data' => [
503
						'message' => (string)$this->l10n->t('Authentication error')
504
					]
505
				],
506
				Http::STATUS_FORBIDDEN
507
			);
508
		}
509
510
		if($user) {
511
			if($user->delete()) {
512
				return new DataResponse(
513
					[
514
						'status' => 'success',
515
						'data' => [
516
							'username' => $id
517
						]
518
					],
519
					Http::STATUS_NO_CONTENT
520
				);
521
			}
522
		}
523
524
		return new DataResponse(
525
			[
526
				'status' => 'error',
527
				'data' => [
528
					'message' => (string)$this->l10n->t('Unable to delete user.')
529
				]
530
			],
531
			Http::STATUS_FORBIDDEN
532
		);
533
	}
534
535
	/**
536
	 * Set the mail address of a user
537
	 *
538
	 * @NoAdminRequired
539
	 * @NoSubadminRequired
540
	 *
541
	 * @param string $id
542
	 * @param string $mailAddress
543
	 * @return DataResponse
544
	 */
545
	public function setMailAddress($id, $mailAddress) {
546
		$userId = $this->userSession->getUser()->getUID();
547
		$user = $this->userManager->get($id);
548
549 View Code Duplication
		if($userId !== $id
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
550
			&& !$this->isAdmin
551
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, isUserAccessible() 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...
Bug introduced by
It seems like $user defined by $this->userManager->get($id) on line 547 can be null; however, OCP\ISubAdminManager::isUserAccessible() 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...
552
			return new DataResponse(
553
				[
554
					'status' => 'error',
555
					'data' => [
556
						'message' => (string)$this->l10n->t('Forbidden')
557
					]
558
				],
559
				Http::STATUS_FORBIDDEN
560
			);
561
		}
562
563
		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
564
			return new DataResponse(
565
				[
566
					'status' => 'error',
567
					'data' => [
568
						'message' => (string)$this->l10n->t('Invalid mail address')
569
					]
570
				],
571
				Http::STATUS_UNPROCESSABLE_ENTITY
572
			);
573
		}
574
575 View Code Duplication
		if(!$user){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
576
			return new DataResponse(
577
				[
578
					'status' => 'error',
579
					'data' => [
580
						'message' => (string)$this->l10n->t('Invalid user')
581
					]
582
				],
583
				Http::STATUS_UNPROCESSABLE_ENTITY
584
			);
585
		}
586
587
		// this is the only permission a backend provides and is also used
588
		// for the permission of setting a email address
589 View Code Duplication
		if(!$user->canChangeDisplayName()){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
590
			return new DataResponse(
591
				[
592
					'status' => 'error',
593
					'data' => [
594
						'message' => (string)$this->l10n->t('Unable to change mail address')
595
					]
596
				],
597
				Http::STATUS_FORBIDDEN
598
			);
599
		}
600
601
		// admins can set email without verification
602 View Code Duplication
		if ($mailAddress === '' || $this->isAdmin) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
603
			$this->setEmailAddress($userId, $mailAddress);
604
			return new DataResponse(
605
				[
606
					'status' => 'success',
607
					'data' => [
608
						'message' => (string)$this->l10n->t('Email has been changed successfully.')
609
					]
610
				],
611
				Http::STATUS_OK
612
			);
613
		}
614
615
		try {
616
			if ($this->sendEmail($userId, $mailAddress)) {
617
				return new DataResponse(
618
					[
619
						'status' => 'success',
620
						'data' => [
621
							'username' => $id,
622
							'mailAddress' => $mailAddress,
623
							'message' => (string) $this->l10n->t('An email has been sent to this address for confirmation')
624
						]
625
					],
626
					Http::STATUS_OK
627
				);
628 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
629
				return new DataResponse(
630
					[
631
						'status' => 'error',
632
						'data' => [
633
							'username' => $id,
634
							'mailAddress' => $mailAddress,
635
							'message' => (string) $this->l10n->t('No email was sent because you already sent one recently. Please try again later.')
636
						]
637
					],
638
					Http::STATUS_OK
639
				);
640
			}
641
642
		} catch (\Exception $e){
643
			return new DataResponse(
644
				[
645
					'status' => 'error',
646
					'data' => [
647
						'message' => (string)$e->getMessage()
648
					]
649
				]
650
			);
651
		}
652
653
	}
654
655
	/**
656
	 * Count all unique users visible for the current admin/subadmin.
657
	 *
658
	 * @NoAdminRequired
659
	 *
660
	 * @return DataResponse
661
	 */
662
	public function stats() {
663
		$userCount = 0;
664
		if ($this->isAdmin) {
665
			$countByBackend = $this->userManager->countUsers();
666
667
			if (!empty($countByBackend)) {
668
				foreach ($countByBackend as $count) {
669
					$userCount += $count;
670
				}
671
			}
672
		} else {
673
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, getSubAdminsGroups() 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...
674
675
			$uniqueUsers = [];
676
			foreach ($groups as $group) {
677
				foreach($group->getUsers() as $uid => $displayName) {
678
					$uniqueUsers[$uid] = true;
679
				}
680
			}
681
682
			$userCount = count($uniqueUsers);
683
		}
684
685
		return new DataResponse(
686
			[
687
				'totalUsers' => $userCount
688
			]
689
		);
690
	}
691
692
693
	/**
694
	 * Set the displayName of a user
695
	 *
696
	 * @NoAdminRequired
697
	 * @NoSubadminRequired
698
	 *
699
	 * @param string $username
700
	 * @param string $displayName
701
	 * @return DataResponse
702
	 */
703
	public function setDisplayName($username, $displayName) {
704
		$currentUser = $this->userSession->getUser();
705
706
		if ($username === null) {
707
			$username = $currentUser->getUID();
708
		}
709
710
		$user = $this->userManager->get($username);
711
712
		if ($user === null ||
713
			!$user->canChangeDisplayName() ||
714
			(
715
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
716
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
0 ignored issues
show
Bug introduced by
It seems like $currentUser defined by $this->userSession->getUser() on line 704 can be null; however, OCP\ISubAdminManager::isUserAccessible() 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...
717
				$currentUser !== $user)
718
			) {
719
			return new DataResponse([
720
				'status' => 'error',
721
				'data' => [
722
					'message' => $this->l10n->t('Authentication error'),
723
				],
724
			]);
725
		}
726
727
		if ($user->setDisplayName($displayName)) {
728
			return new DataResponse([
729
				'status' => 'success',
730
				'data' => [
731
					'message' => $this->l10n->t('Your full name has been changed.'),
732
					'username' => $username,
733
					'displayName' => $displayName,
734
				],
735
			]);
736 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
737
			return new DataResponse([
738
				'status' => 'error',
739
				'data' => [
740
					'message' => $this->l10n->t('Unable to change full name'),
741
					'displayName' => $user->getDisplayName(),
742
				],
743
			]);
744
		}
745
	}
746
747
	/**
748
 	 * @param string $userId
749
 	 * @param string $mailAddress
750
 	 * @throws \Exception
751
	 * @return boolean
752
 	 */
753
	public function sendEmail($userId, $mailAddress) {
754
		$token = $this->config->getUserValue($userId, 'owncloud', 'changeMail');
755 View Code Duplication
		if ($token !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
756
			$splittedToken = explode(':', $token);
757
			if ((count($splittedToken)) === 3 && $splittedToken[0] > ($this->timeFactory->getTime() - 60 * 5)) {
758
				$this->log->alert('The email is not sent because an email change confirmation mail was sent recently.');
759
				return false;
760
			}
761
		}
762
763
		$token = $this->secureRandom->generate(21,
764
			ISecureRandom::CHAR_DIGITS .
765
			ISecureRandom::CHAR_LOWER .
766
			ISecureRandom::CHAR_UPPER);
767
		$this->config->setUserValue($userId, 'owncloud', 'changeMail', $this->timeFactory->getTime() . ':' . $token . ':' . $mailAddress);
768
769
		$link = $this->urlGenerator->linkToRouteAbsolute('settings.Users.changeMail', ['userId' => $userId, 'token' => $token]);
770
771
		$tmpl = new \OC_Template('settings', 'changemail/email');
772
		$tmpl->assign('link', $link);
773
		$msg = $tmpl->fetchPage();
774
775
		try {
776
			$message = $this->mailer->createMessage();
777
			$message->setTo([$mailAddress => $userId]);
778
			$message->setSubject($this->l10n->t('%s email address confirm', [$this->defaults->getName()]));
779
			$message->setPlainBody($msg);
0 ignored issues
show
Bug introduced by
It seems like $msg defined by $tmpl->fetchPage() on line 773 can also be of type boolean; however, OC\Mail\Message::setPlainBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
780
			$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
781
			$this->mailer->send($message);
782
		} catch (\Exception $e) {
783
			throw new \Exception($this->l10n->t(
784
				'Couldn\'t send email address change confirmation mail. Please contact your administrator.'
785
			));
786
		}
787
		return true;
788
    }
789
790
	/**
791
	 * @NoAdminRequired
792
	 *
793
	 * @param string $id
794
 	 * @param string $mailAddress
795
 	 */
796
	public function setEmailAddress($id, $mailAddress) {
797
		$user = $this->userManager->get($id);
798
799
		// Only Admin and SubAdmins are allowed to set email
800
		if($this->isAdmin ||
801
			($this->groupManager->getSubAdmin()->isSubAdmin($this->userSession->getUser()) &&
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, isSubAdmin() 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...
802
				$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user))) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, isUserAccessible() 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...
Bug introduced by
It seems like $user defined by $this->userManager->get($id) on line 797 can be null; however, OCP\ISubAdminManager::isUserAccessible() 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...
803
			$user->setEMailAddress($mailAddress);
804
			if ($this->config->getUserValue($id, 'owncloud', 'changeMail') !== '') {
805
				$this->config->deleteUserValue($id, 'owncloud', 'changeMail');
806
			}
807
		} else {
808
			return new JSONResponse([
809
				'error' => 'cannotSetEmailAddress',
810
				'message' => 'Cannot set email address for user'
811
			], HTTP::STATUS_NOT_FOUND);
812
		}
813
	}
814
815
	/**
816
	 * @NoCSRFRequired
817
	 * @NoAdminRequired
818
	 * @NoSubadminRequired
819
	 *
820
	 * @param $token
821
	 * @param $userId
822
	 * @return RedirectResponse
823
	 * @throws \Exception
824
	 */
825
	public function changeMail($token, $userId) {
826
		$user = $this->userManager->get($userId);
827
		$sessionUser = $this->userSession->getUser();
828
829
		if ($user !== $sessionUser) {
830
			$this->log->error("The logged in user is different than expected.", ['app' => 'settings']);
831
			return new RedirectResponse($this->urlGenerator->linkToRoute('settings.SettingsPage.getPersonal', ['changestatus' => 'error']));
832
		}
833
834
		try {
835
			$this->checkEmailChangeToken($token, $userId);
836
		} catch (\Exception $e) {
837
			$this->log->error($e->getMessage(), ['app' => 'settings']);
838
			return new RedirectResponse($this->urlGenerator->linkToRoute('settings.SettingsPage.getPersonal', ['changestatus' => 'error']));
839
		}
840
841
		$oldEmailAddress = $user->getEMailAddress();
842
843
		$splittedToken = explode(':', $this->config->getUserValue($userId, 'owncloud', 'changeMail', null));
844
		$mailAddress = $splittedToken[2];
845
846
		$this->setEmailAddress($userId, $mailAddress);
847
848
		if ($oldEmailAddress !== null && $oldEmailAddress !== '') {
849
			$tmpl = new \OC_Template('settings', 'changemail/notify');
850
			$tmpl->assign('mailAddress', $mailAddress);
851
			$msg = $tmpl->fetchPage();
852
853
			try {
854
				$message = $this->mailer->createMessage();
855
				$message->setTo([$oldEmailAddress => $userId]);
856
				$message->setSubject($this->l10n->t('%s email address changed successfully', [$this->defaults->getName()]));
857
				$message->setPlainBody($msg);
0 ignored issues
show
Bug introduced by
It seems like $msg defined by $tmpl->fetchPage() on line 851 can also be of type boolean; however, OC\Mail\Message::setPlainBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
858
				$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
859
				$this->mailer->send($message);
860
			} catch (\Exception $e) {
861
				throw new \Exception($this->l10n->t(
862
					'Couldn\'t send email address change notification mail. Please contact your administrator.'
863
				));
864
			}
865
		}
866
		return new RedirectResponse($this->urlGenerator->linkToRoute('settings.SettingsPage.getPersonal', ['changestatus' => 'success']));
867
  }
868
  
869
  /*
870
	 * @NoAdminRequired
871
	 *
872
	 * @param string $id
873
	 * @return DataResponse
874
	 */
875
	public function setEnabled($id, $enabled) {
876
                $userId = $this->userSession->getUser()->getUID();
877
                $user = $this->userManager->get($id);
878
879 View Code Duplication
                if($userId === $id ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
880
                        (!$this->isAdmin &&
881
                        !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user))) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, isUserAccessible() 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...
Bug introduced by
It seems like $user defined by $this->userManager->get($id) on line 877 can be null; however, OCP\ISubAdminManager::isUserAccessible() 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...
882
                        return new DataResponse(
883
                                array(
884
                                        'status' => 'error',
885
                                        'data' => array(
886
                                                'message' => (string)$this->l10n->t('Forbidden')
887
                                        )
888
                                ),
889
                                Http::STATUS_FORBIDDEN
890
                        );
891
                }
892
893
894 View Code Duplication
                if(!$user){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
895
                        return new DataResponse(
896
                                array(
897
                                        'status' => 'error',
898
                                        'data' => array(
899
                                                'message' => (string)$this->l10n->t('Invalid user')
900
                                        )
901
                                ),
902
                                Http::STATUS_UNPROCESSABLE_ENTITY
903
                        );
904
                }
905
906
907
		$value = filter_var($enabled, FILTER_VALIDATE_BOOLEAN);
908 View Code Duplication
		if(!isset($value) || is_null($value))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
909
		{
910
                        return new DataResponse(
911
                                array(
912
                                        'status' => 'error',
913
                                        'data' => array(
914
                                                'message' => (string)$this->l10n->t('Unable to enable/disable user.')
915
                                        )
916
                                ),
917
                                Http::STATUS_FORBIDDEN
918
                        );
919
		}
920
921
		$user->setEnabled($value);
922
923
		return new DataResponse(
924
			[
925
				'status' => 'success',
926
				'data' => [
927
					'username' => $id,
928
					'enabled' => $enabled
929
				]
930
			],
931
			Http::STATUS_OK
932
		);
933
	}
934
935 View Code Duplication
	private function isAdmin() {
936
		// Check if current user (active and not in incognito mode)
937
		// is an admin
938
		$activeUser = $this->userSession->getUser();
939
		if($activeUser !== null) {
940
			return $this->groupManager->isAdmin($activeUser->getUID());
941
		}
942
		return false;
943
	}
944
}
945